Skip to content

Commit

Permalink
feat: added workload identity federation
Browse files Browse the repository at this point in the history
  • Loading branch information
Myroslav Levchyk authored and Myroslav Levchyk committed Apr 5, 2024
1 parent f183ae3 commit 3c87942
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 0 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,59 @@ Terraform module for creation Azure <>
## Usage

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
| <a name="requirement_azuredevops"></a> [azuredevops](#requirement\_azuredevops) | =0.11.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | >= 3.40.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azuredevops"></a> [azuredevops](#provider\_azuredevops) | =0.11.0 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | >= 3.40.0 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [azuredevops_serviceendpoint_azurerm.this](https://registry.terraform.io/providers/microsoft/azuredevops/0.11.0/docs/resources/serviceendpoint_azurerm) | resource |
| [azurerm_federated_identity_credential.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/federated_identity_credential) | resource |
| [azurerm_key_vault_access_policy.assigned_identity](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
| [azurerm_role_assignment.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_user_assigned_identity.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource |
| [azuredevops_project.this](https://registry.terraform.io/providers/microsoft/azuredevops/0.11.0/docs/data-sources/project) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_ado_project_name"></a> [ado\_project\_name](#input\_ado\_project\_name) | ADO Project Name | `string` | n/a | yes |
| <a name="input_ado_workload_identity_federation_enabled"></a> [ado\_workload\_identity\_federation\_enabled](#input\_ado\_workload\_identity\_federation\_enabled) | Workload Identity Federation enable | `bool` | `true` | no |
| <a name="input_custom_federated_identity_credential_name"></a> [custom\_federated\_identity\_credential\_name](#input\_custom\_federated\_identity\_credential\_name) | Specifies the name of the Federated Identity Credential | `string` | `""` | no |
| <a name="input_custom_serviceendpoint_name"></a> [custom\_serviceendpoint\_name](#input\_custom\_serviceendpoint\_name) | Specifies the name of the ADO Service Connection | `string` | `""` | no |
| <a name="input_key_vault_policy_config"></a> [key\_vault\_policy\_config](#input\_key\_vault\_policy\_config) | List of object with parameters to create Key Vault Access Policy | <pre>list(object({<br> key_vault_name = string<br> key_vault_id = string<br> tenant_id = string<br> key_permissions = optional(list(string), ["Get", "List", "Encrypt", "Decrypt"])<br> secret_permissions = optional(list(string), ["Get", "List"])<br> }))</pre> | `[]` | no |
| <a name="input_location"></a> [location](#input\_location) | Azure Region | `string` | n/a | yes |
| <a name="input_resource_group"></a> [resource\_group](#input\_resource\_group) | The name of the resource group | `string` | n/a | yes |
| <a name="input_role_assignment_scope"></a> [role\_assignment\_scope](#input\_role\_assignment\_scope) | ADO Service Connection target Subscription Id | `string` | n/a | yes |
| <a name="input_role_assignments_allowed"></a> [role\_assignments\_allowed](#input\_role\_assignments\_allowed) | This variable determines whether Service Principal used by Terraform can assign Roles to Azure resources | `bool` | `true` | no |
| <a name="input_subscription_id"></a> [subscription\_id](#input\_subscription\_id) | ADO Service Connection target Subscription Id | `string` | n/a | yes |
| <a name="input_tenant_id"></a> [tenant\_id](#input\_tenant\_id) | ADO Service Connection target Tenant Id | `string` | n/a | yes |
| <a name="input_user_assigned_identity_name"></a> [user\_assigned\_identity\_name](#input\_user\_assigned\_identity\_name) | Specifies the name of the User Assigned Identity | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_azurerm_user_assigned_identity_name"></a> [azurerm\_user\_assigned\_identity\_name](#output\_azurerm\_user\_assigned\_identity\_name) | Built name of single User Assigned Identity |
| <a name="output_user_assigned_identity_principal_id"></a> [user\_assigned\_identity\_principal\_id](#output\_user\_assigned\_identity\_principal\_id) | Built principal id of single User Assigned Identity |
<!-- END_TF_DOCS -->

## License
Expand Down
58 changes: 58 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
locals {
key_vault_policy_config_mapped = { for object in var.key_vault_policy_config : object.key_vault_name => object }
}

data "azuredevops_project" "this" {
name = var.ado_project_name
}

resource "azurerm_user_assigned_identity" "this" {
name = var.user_assigned_identity_name
resource_group_name = var.resource_group
location = var.location
}

resource "azuredevops_serviceendpoint_azurerm" "this" {
count = var.ado_workload_identity_federation_enabled ? 1 : 0

project_id = data.azuredevops_project.this.project_id
service_endpoint_name = coalesce(var.custom_serviceendpoint_name, "federated-(${var.subscription_id})-${var.user_assigned_identity_name}")
description = "Managed by Terraform"
service_endpoint_authentication_scheme = "WorkloadIdentityFederation"
credentials {
serviceprincipalid = azurerm_user_assigned_identity.this.client_id
}
azurerm_spn_tenantid = var.tenant_id
azurerm_subscription_id = var.subscription_id
azurerm_subscription_name = "Example Subscription Name"
}

resource "azurerm_federated_identity_credential" "this" {
count = var.ado_workload_identity_federation_enabled ? 1 : 0

name = coalesce(var.custom_federated_identity_credential_name, "federated-${var.user_assigned_identity_name}")
resource_group_name = var.resource_group
parent_id = azurerm_user_assigned_identity.this.id
audience = ["api://AzureADTokenExchange"]
issuer = azuredevops_serviceendpoint_azurerm.this[0].workload_identity_federation_issuer
subject = azuredevops_serviceendpoint_azurerm.this[0].workload_identity_federation_subject
}


resource "azurerm_role_assignment" "this" {
count = alltrue([var.ado_workload_identity_federation_enabled, var.role_assignments_allowed]) ? 1 : 0

principal_id = azurerm_user_assigned_identity.this.principal_id
scope = var.role_assignment_scope
role_definition_name = "Reader"
}

resource "azurerm_key_vault_access_policy" "assigned_identity" {
for_each = var.ado_workload_identity_federation_enabled ? local.key_vault_policy_config_mapped : {}

object_id = azurerm_user_assigned_identity.this.principal_id
key_vault_id = each.value.key_vault_id
tenant_id = each.value.tenant_id
key_permissions = each.value.key_permissions
secret_permissions = each.value.secret_permissions
}
9 changes: 9 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "azurerm_user_assigned_identity_name" {
description = "Built name of single User Assigned Identity"
value = try(azurerm_user_assigned_identity.this.name, null)
}

output "user_assigned_identity_principal_id" {
description = "Built principal id of single User Assigned Identity"
value = try(azurerm_user_assigned_identity.this.principal_id, null)
}
68 changes: 68 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
variable "location" {
type = string
description = "Azure Region"
}

variable "resource_group" {
description = "The name of the resource group"
type = string
}

variable "ado_workload_identity_federation_enabled" {
description = "Workload Identity Federation enable"
default = true
}

variable "role_assignments_allowed" {
description = "This variable determines whether Service Principal used by Terraform can assign Roles to Azure resources"
default = true
}

variable "user_assigned_identity_name" {
type = string
description = "Specifies the name of the User Assigned Identity"
}

variable "custom_serviceendpoint_name" {
type = string
description = "Specifies the name of the ADO Service Connection"
default = ""
}

variable "custom_federated_identity_credential_name" {
type = string
description = "Specifies the name of the Federated Identity Credential"
default = ""
}

variable "ado_project_name" {
type = string
description = "ADO Project Name"
}

variable "role_assignment_scope" {
type = string
description = "ADO Service Connection target Subscription Id"
}

variable "subscription_id" {
type = string
description = "ADO Service Connection target Subscription Id"
}

variable "tenant_id" {
type = string
description = "ADO Service Connection target Tenant Id"
}

variable "key_vault_policy_config" {
description = "List of object with parameters to create Key Vault Access Policy"
type = list(object({
key_vault_name = string
key_vault_id = string
tenant_id = string
key_permissions = optional(list(string), ["Get", "List", "Encrypt", "Decrypt"])
secret_permissions = optional(list(string), ["Get", "List"])
}))
default = []
}
14 changes: 14 additions & 0 deletions versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.0.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.40.0"
}
azuredevops = {
source = "microsoft/azuredevops"
version = "=0.11.0"
}
}
}

0 comments on commit 3c87942

Please sign in to comment.