Skip to content

Commit

Permalink
Add modules for Kubernetes pod identity, storage class, and service a…
Browse files Browse the repository at this point in the history
…ccount

This commit introduces three new Terraform modules: Kubernetes pod identity, storage class, and service account, along with their README documentation, main configuration files, and required variables/outputs definitions. These modules simplify the creation and management of related Kubernetes resources, including support for ZRS storage redundancies and custom configurations.
  • Loading branch information
ffppa committed Jan 28, 2025
1 parent d32255e commit 0d87e1a
Show file tree
Hide file tree
Showing 17 changed files with 643 additions and 0 deletions.
76 changes: 76 additions & 0 deletions kubernetes_pod_identity/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# kubernetes pod identity

Module that allows the creation of a pod identity. Check <https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity#create-an-aks-cluster-with-kubenet-network-plugin> or <https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity#run-a-sample-application> for more information.

## Architecture

![architecture](./docs/module-arch.drawio.png)

## How to use it

```hcl
module "domain_pod_identity" {
source = "git::https://github.com/pagopa/terraform-azurerm-v3.git//kubernetes_pod_identity?ref=v8.8.0"
resource_group_name = local.aks_resource_group_name
location = var.location
tenant_id = data.azurerm_subscription.current.tenant_id
cluster_name = local.aks_name
identity_name = "${var.domain}-pod-identity"
namespace = kubernetes_namespace.domain_namespace.metadata[0].name
key_vault_id = data.azurerm_key_vault.kv.id
secret_permissions = ["Get"]
}
```

## Migration from v2

1️⃣ Arguments changed:

* `certificate_permissions`, `key_permissions` and `secret_permissions` related to keyvault access policy, must start with a capitol letter. E.g [Backup Delete Get List Purge Recover Restore Set]

<!-- markdownlint-disable -->
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 4 |
| <a name="requirement_null"></a> [null](#requirement\_null) | ~> 3.2 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [azurerm_key_vault_access_policy.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
| [azurerm_user_assigned_identity.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource |
| [null_resource.create_pod_identity](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_certificate_permissions"></a> [certificate\_permissions](#input\_certificate\_permissions) | (Optional) API permissions of the identity to access certificates, must be one or more from the following: Backup, Create, Delete, DeleteIssuers, Get, GetIssuers, Import, List, ListIssuers, ManageContacts, ManageIssuers, Purge, Recover, Restore, SetIssuers and Update. | `list(string)` | `[]` | no |
| <a name="input_cluster_name"></a> [cluster\_name](#input\_cluster\_name) | (Required) Name of the Kubernetes cluster. | `string` | n/a | yes |
| <a name="input_identity_name"></a> [identity\_name](#input\_identity\_name) | (Required) The name of the user assigned identity and POD identity. Changing this forces a new identity to be created. | `string` | n/a | yes |
| <a name="input_key_permissions"></a> [key\_permissions](#input\_key\_permissions) | (Optional) API permissions of the identity to access keys, must be one or more from the following: Backup, Create, Decrypt, Delete, Encrypt, Get, Import, List, Purge, Recover, Restore, Sign, UnwrapKey, Update, Verify and WrapKey. | `list(string)` | `[]` | no |
| <a name="input_key_vault_id"></a> [key\_vault\_id](#input\_key\_vault\_id) | (Required) Specifies the id of the Key Vault resource. Changing this forces a new resource to be created. | `any` | `null` | no |
| <a name="input_location"></a> [location](#input\_location) | (Required) Location of the Kubernetes cluster. | `string` | n/a | yes |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | (Required) Kubernetes namespace where the pod identity will be create. | `string` | n/a | yes |
| <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name) | (Required) Resource group of the Kubernetes cluster. | `string` | n/a | yes |
| <a name="input_secret_permissions"></a> [secret\_permissions](#input\_secret\_permissions) | (Optional) API permissions of the identity to access secrets, must be one or more from the following: Backup, Delete, Get, List, Purge, Recover, Restore and Set. | `list(string)` | `[]` | no |
| <a name="input_tenant_id"></a> [tenant\_id](#input\_tenant\_id) | (Required) The Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Changing this forces a new resource to be created. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_identity"></a> [identity](#output\_identity) | n/a |
<!-- END_TF_DOCS -->
1 change: 1 addition & 0 deletions kubernetes_pod_identity/docs/module-arch.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-05-15T10:39:07.009Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/18.0.1 Chrome/100.0.4896.143 Electron/18.2.0 Safari/537.36" etag="32u4EsUtBPwvBhMiF-ET" version="18.0.1" type="device"><diagram id="ozIA6NuR--no_rFxZAqq" name="Page-1">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</diagram></mxfile>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
76 changes: 76 additions & 0 deletions kubernetes_pod_identity/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
resource "azurerm_user_assigned_identity" "this" {
name = var.identity_name

resource_group_name = var.resource_group_name
location = var.location
}

resource "azurerm_key_vault_access_policy" "this" {
count = var.key_vault_id == null ? 0 : 1

key_vault_id = var.key_vault_id
tenant_id = var.tenant_id

# The object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault.
object_id = azurerm_user_assigned_identity.this.principal_id

certificate_permissions = var.certificate_permissions
key_permissions = var.key_permissions
secret_permissions = var.secret_permissions

depends_on = [
azurerm_user_assigned_identity.this
]
}

resource "null_resource" "create_pod_identity" {
triggers = {
resource_group = var.resource_group_name
cluster_name = var.cluster_name
namespace = var.namespace
name = var.identity_name
identity_id = azurerm_user_assigned_identity.this.id
}

provisioner "local-exec" {
command = <<EOT
echo "🔨 start creation pod Identity"
az aks pod-identity add \
--resource-group ${self.triggers.resource_group} \
--cluster-name ${self.triggers.cluster_name} \
--namespace ${self.triggers.namespace} \
--name ${self.triggers.name} \
--verbose \
--identity-resource-id ${self.triggers.identity_id} && echo "✅ podIdentity created" || echo "❌ Error during podIdentity creation"
echo "✅ pod identity created"
az aks pod-identity list \
--resource-group ${self.triggers.resource_group} \
--cluster-name ${self.triggers.cluster_name} \
--query 'podIdentityProfile.userAssignedIdentities[].{name:name, state:provisioningState}' || true
EOT
}

provisioner "local-exec" {
when = destroy
command = <<EOT
echo "🔨 start destroy pod Identity"
az aks pod-identity delete \
--verbose \
--resource-group ${self.triggers.resource_group} \
--cluster-name ${self.triggers.cluster_name} \
--namespace ${self.triggers.namespace} \
--name ${self.triggers.name} && echo "✅ podIdentity deleted" || echo "❌ Error during podIdentity delete"
az aks pod-identity list \
--resource-group ${self.triggers.resource_group} \
--cluster-name ${self.triggers.cluster_name} \
--query 'podIdentityProfile.userAssignedIdentities[].{name:name, state:provisioningState}' || true
EOT
}

depends_on = [
azurerm_user_assigned_identity.this
]
}
3 changes: 3 additions & 0 deletions kubernetes_pod_identity/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "identity" {
value = azurerm_user_assigned_identity.this
}
60 changes: 60 additions & 0 deletions kubernetes_pod_identity/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
variable "location" {
type = string
description = "(Required) Location of the Kubernetes cluster."
}

variable "tenant_id" {
type = string
description = "(Required) The Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Changing this forces a new resource to be created."
}

variable "key_vault_id" {
type = any
description = "(Required) Specifies the id of the Key Vault resource. Changing this forces a new resource to be created."
default = null
}

#
# AKS
#

variable "resource_group_name" {
type = string
description = "(Required) Resource group of the Kubernetes cluster."
}

variable "cluster_name" {
type = string
description = "(Required) Name of the Kubernetes cluster."
}

variable "namespace" {
type = string
description = "(Required) Kubernetes namespace where the pod identity will be create."
}

variable "identity_name" {
type = string
description = "(Required) The name of the user assigned identity and POD identity. Changing this forces a new identity to be created."
}

#
# Key Vault Permissions
#
variable "secret_permissions" {
type = list(string)
description = "(Optional) API permissions of the identity to access secrets, must be one or more from the following: Backup, Delete, Get, List, Purge, Recover, Restore and Set."
default = []
}

variable "key_permissions" {
type = list(string)
description = "(Optional) API permissions of the identity to access keys, must be one or more from the following: Backup, Create, Decrypt, Delete, Encrypt, Get, Import, List, Purge, Recover, Restore, Sign, UnwrapKey, Update, Verify and WrapKey."
default = []
}

variable "certificate_permissions" {
type = list(string)
description = "(Optional) API permissions of the identity to access certificates, must be one or more from the following: Backup, Create, Delete, DeleteIssuers, Get, GetIssuers, Import, List, ListIssuers, ManageContacts, ManageIssuers, Purge, Recover, Restore, SetIssuers and Update."
default = []
}
14 changes: 14 additions & 0 deletions kubernetes_pod_identity/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.9.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4"
}
null = {
source = "hashicorp/null"
version = "~> 3.2"
}
}
}
52 changes: 52 additions & 0 deletions kubernetes_service_account/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# kubernetes service account

This module creates a service account and its related secrets



## How to use it

```hcl
module "kubernetes_service_account" {
source = "git::https://github.com/pagopa/terraform-azurerm-v3.git//kubernetes_service_account?ref=v8.8.0"
name = "azure-devops"
namespace = local.system_domain_namespace
}
```

<!-- markdownlint-disable -->
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | ~> 2.27 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [kubernetes_secret_v1.azure_devops_service_account_default_secret](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource |
| [kubernetes_service_account.azure_devops](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_account) | resource |
| [kubernetes_secret.azure_devops_secret](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/data-sources/secret) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_custom_service_account_default_secret_name"></a> [custom\_service\_account\_default\_secret\_name](#input\_custom\_service\_account\_default\_secret\_name) | Service account custom secret name | `string` | `""` | no |
| <a name="input_name"></a> [name](#input\_name) | Service account name | `string` | n/a | yes |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Service account namespace | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_sa_ca_cert"></a> [sa\_ca\_cert](#output\_sa\_ca\_cert) | n/a |
| <a name="output_sa_token"></a> [sa\_token](#output\_sa\_token) | n/a |
<!-- END_TF_DOCS -->
39 changes: 39 additions & 0 deletions kubernetes_service_account/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
resource "kubernetes_service_account" "azure_devops" {
metadata {
name = var.name
namespace = var.namespace
}
automount_service_account_token = false
}

resource "kubernetes_secret_v1" "azure_devops_service_account_default_secret" {
metadata {
name = local.service_account_default_secret_name
namespace = var.namespace
annotations = {
"kubernetes.io/service-account.name" = var.name
}
}

depends_on = [kubernetes_service_account.azure_devops]

type = "kubernetes.io/service-account-token"
}

#
# Secrets service account on KV
#
data "kubernetes_secret" "azure_devops_secret" {
metadata {
name = local.service_account_default_secret_name
namespace = var.namespace
}
binary_data = {
"ca.crt" = ""
"token" = ""
}

depends_on = [
kubernetes_secret_v1.azure_devops_service_account_default_secret
]
}
7 changes: 7 additions & 0 deletions kubernetes_service_account/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
output "sa_token" {
value = data.kubernetes_secret.azure_devops_secret.binary_data["token"]
}

output "sa_ca_cert" {
value = data.kubernetes_secret.azure_devops_secret.binary_data["ca.crt"]
}
21 changes: 21 additions & 0 deletions kubernetes_service_account/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
locals {
service_account_default_secret_name = var.custom_service_account_default_secret_name == "" ? "${var.name}-sa-token" : var.custom_service_account_default_secret_name
}

variable "name" {
type = string
description = "Service account name"
}

variable "namespace" {
type = string
description = "Service account namespace"
}

variable "custom_service_account_default_secret_name" {
type = string
description = "Service account custom secret name"
default = ""
}


10 changes: 10 additions & 0 deletions kubernetes_service_account/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.9.0"

required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.27"
}
}
}
Loading

0 comments on commit 0d87e1a

Please sign in to comment.