Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #45: Adds vault module #47

62 changes: 56 additions & 6 deletions apply-terraform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,35 @@ stages:
- job: TerraformInitPlan
displayName: "Terraform Init and Plan"
steps:
- task: AzureCLI@2
displayName: "Azure CLI Login"
inputs:
azureSubscription: $(serviceConnectionName)
scriptType: "bash"
scriptLocation: "inlineScript"
inlineScript: |
echo "Successfully logged in with Azure CLI"

- task: AzureCLI@2
displayName: "Get AKS Credentials"
inputs:
azureSubscription: $(serviceConnectionName)
scriptType: "bash"
scriptLocation: "inlineScript"
inlineScript: |
az aks get-credentials \
--name $(aks-name) \
--resource-group $(aks-resource-group) \
--admin \
--file ~/.kube/config
echo "AKS credentials configured for kubectl"

- task: DownloadSecureFile@1
name: DownloadSecureVars
displayName: 'Download staging.tfvars'
displayName: "Download staging.tfvars"
inputs:
secureFile: 'staging.tfvars'
secureFile: "staging.tfvars"

- task: TerraformTaskV2@2
displayName: Terra Init
inputs:
Expand All @@ -35,12 +59,13 @@ stages:
backendAzureRmStorageAccountName: "$(storageAccountName)"
backendAzureRmContainerName: "$(containerName)"
backendAzureRmKey: "$(stateKey)"

- task: TerraformTaskV2@2
displayName: Terra Plan
inputs:
provider: "azurerm"
command: "plan"
commandOptions: '-var-file=$(DownloadSecureVars.SecureFilePath)'
commandOptions: "-var-file=$(DownloadSecureVars.SecureFilePath)"
workingDirectory: "$(System.DefaultWorkingDirectory)/terraform/staging"
environmentServiceNameAzureRM: "$(serviceConnectionName)"

Expand All @@ -59,11 +84,36 @@ stages:
deploy:
steps:
- checkout: self

- task: AzureCLI@2
displayName: "Azure CLI Login"
inputs:
azureSubscription: $(serviceConnectionName)
scriptType: "bash"
scriptLocation: "inlineScript"
inlineScript: |
echo "Successfully logged in with Azure CLI"

- task: AzureCLI@2
displayName: "Get AKS Credentials"
inputs:
azureSubscription: $(serviceConnectionName)
scriptType: "bash"
scriptLocation: "inlineScript"
inlineScript: |
az aks get-credentials \
--name $(aks-name) \
--resource-group $(aks-resource-group) \
--admin \
--file ~/.kube/config
echo "AKS credentials configured for kubectl"

- task: DownloadSecureFile@1
name: DownloadSecureVars
displayName: 'Download staging.tfvars'
displayName: "Download staging.tfvars"
inputs:
secureFile: 'staging.tfvars'
secureFile: "staging.tfvars"

- task: TerraformTaskV2@2
displayName: Terra Init
inputs:
Expand All @@ -80,6 +130,6 @@ stages:
inputs:
provider: "azurerm"
command: "apply"
commandOptions: '-var-file=$(DownloadSecureVars.SecureFilePath)'
commandOptions: "-var-file=$(DownloadSecureVars.SecureFilePath)"
workingDirectory: "$(System.DefaultWorkingDirectory)/terraform/staging"
environmentServiceNameAzureRM: "$(serviceConnectionName)"
18 changes: 13 additions & 5 deletions kubernetes/system/vault/vault.yml
Original file line number Diff line number Diff line change
Expand Up @@ -826,15 +826,23 @@ server:
}
}

seal "gcpckms" {
project = "spartan-rhino-408115"
region = "northamerica-northeast1"
key_ring = "vault-keyring-gcp"
crypto_key = "vault-cryptokey-gcp"

seal "azurekeyvault" {
tenant_id = "YOUR-AZURE-TENANT-ID"
vault_name = "staging-vault
key_name = "staging-vault-unseal"
resource = "https://managedhsm.azure.net"
}

service_registration "kubernetes" {}

# unseal for gcp kms setup
# seal "gcpckms" {
# project = "spartan-rhino-408115"
# region = "northamerica-northeast1"
# key_ring = "vault-keyring-gcp"
# crypto_key = "vault-cryptokey-gcp"
# }
# A disruption budget limits the number of pods of a replicated application
# that are down simultaneously from voluntary disruptions
disruptionBudget:
Expand Down
6 changes: 6 additions & 0 deletions terraform/modules/azure-kubernetes-cluster/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ resource "azurerm_kubernetes_cluster" "k8s" {
pod_cidr = var.pod_cidr
}

lifecycle {
ignore_changes = [
default_node_pool
]
}

tags = var.tags

sku_tier = var.sku_tier
Expand Down
10 changes: 10 additions & 0 deletions terraform/modules/azure-kubernetes-cluster/output.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@ output "cluster_name" {
description = "Cluster name to be used in the context of kubectl"
value = azurerm_kubernetes_cluster.k8s.name
}

output "cluster_ca_certificate" {
description = "Cluster certificate"
value = azurerm_kubernetes_cluster.k8s.kube_config[0].cluster_ca_certificate
}

output "cluster_principal_id" {
description = "AKS cluster principal id"
value = azurerm_kubernetes_cluster.k8s.identity[0].principal_id
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ terraform {
source = "hashicorp/local"
version = "2.4.0"
}
tls = {
source = "hashicorp/tls"
version = "4.0.4"
}
azuread = {
source = "hashicorp/azuread"
version = "2.47.0"
Expand Down
5 changes: 0 additions & 5 deletions terraform/modules/azure-kubernetes-cluster/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,3 @@ data "azurerm_subnet" "subnet" {
virtual_network_name = var.network_vnet
resource_group_name = var.network_resource_group
}


resource "tls_private_key" "pair" {
algorithm = "RSA"
}
13 changes: 13 additions & 0 deletions terraform/modules/vault/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This requires that jq and openssl are installed in the runtime environment
# It creates a certificate signing request (CSR) based on the vault-csr.conf file
# The 2 jq at the beginning and end of the pipes are used to read the input and wrap the result in json
# since this is how terraform "external" passes data.
data "external" "k8s_cert_request" {
program = [
"bash", "-c",
"curl -o jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && chmod +x jq && jq -rc '.key' | openssl req -new -noenc -config ${path.module}/vault-csr.conf -key /dev/stdin | jq -rRncs '{\"request\": inputs}'"
rngadam marked this conversation as resolved.
Show resolved Hide resolved
]
query = {
"key" = tls_private_key.pair.private_key_pem
}
}
103 changes: 103 additions & 0 deletions terraform/modules/vault/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
data "azurerm_client_config" "current" {}

# Needed to provide unique vault name
resource "random_string" "azurerm_key_vault_name" {
length = 5
numeric = true
special = false
upper = false
}

locals {
suffix = random_string.azurerm_key_vault_name.result
}

# Create Azure Key Vault
resource "azurerm_key_vault" "vault" {
name = "${var.prefix}-vault-${local.suffix}"
location = var.location
resource_group_name = var.resource_group
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
soft_delete_retention_days = 7
purge_protection_enabled = false

access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id

key_permissions = var.key_permissions
secret_permissions = var.secret_permissions
}
}

resource "azurerm_key_vault_key" "vault_unseal" {
name = "${var.prefix}-vault-unseal-${local.suffix}"
key_vault_id = azurerm_key_vault.vault.id
key_type = var.key_type
key_size = var.key_size
key_opts = var.key_opts

# Define the rotation policy
rotation_policy {
automatic {
time_before_expiry = "P7D"
}

expire_after = "P28D"
notify_before_expiry = "P7D"
}
}

# Set an access policy for the service principal to the Key Vault
resource "azurerm_key_vault_access_policy" "vault" {
key_vault_id = azurerm_key_vault.vault.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = var.cluster_principal_id

key_permissions = var.aks_key_permissions
secret_permissions = var.aks_secret_permissions
}

# We make ask Kubernetes to sign the certificate
# https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/
resource "kubernetes_certificate_signing_request_v1" "vault_kube_cert_req" {
metadata {
name = "vault.svc"
}
spec {
request = data.external.k8s_cert_request.result["request"]
signer_name = "kubernetes.io/kubelet-serving"
usages = ["digital signature", "key encipherment", "server auth"]
}
auto_approve = true
lifecycle {
ignore_changes = [spec[0].request]
replace_triggered_by = [tls_private_key.pair]
}
}

# Makes sure the vault namespace is created before adding secrets
resource "kubernetes_namespace" "vault_ns" {
metadata {
name = "vault"
labels = {
"pod-security.kubernetes.io/enforce" = "privileged"
}
}
}

resource "kubernetes_secret" "vault_tls" {
metadata {
name = "vault-tls"
namespace = kubernetes_namespace.vault_ns.metadata[0].name
}

data = {
"vault.crt" = kubernetes_certificate_signing_request_v1.vault_kube_cert_req.certificate
rngadam marked this conversation as resolved.
Show resolved Hide resolved
"vault.key" = tls_private_key.pair.private_key_pem
"vault.ca" = var.ca_cluster
}

type = "kubernetes.io/generic"
}
35 changes: 35 additions & 0 deletions terraform/modules/vault/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
terraform {

required_version = ">= 1.7.2"

required_providers {
local = {
source = "hashicorp/local"
version = "2.4.0"
}
tls = {
source = "hashicorp/tls"
version = "4.0.4"
}
external = {
source = "hashicorp/external"
version = "2.3.1"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.24.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.25"
}
azuread = {
source = "hashicorp/azuread"
version = "2.47.0"
}
random = {
source = "hashicorp/random"
version = "~>3.0"
}
}
}
4 changes: 4 additions & 0 deletions terraform/modules/vault/resources.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "tls_private_key" "pair" {
algorithm = "RSA"
rsa_bits = 2048
}
Loading
Loading