Skip to content

Commit 877ef7d

Browse files
authored
Update Terraform doc (#59)
1 parent ffcbd12 commit 877ef7d

File tree

5 files changed

+164
-77
lines changed

5 files changed

+164
-77
lines changed

.github/workflows/docs.yml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
name: Generate terraform docs
22
on:
3-
- pull_request
43
- push
54

65
jobs:
76
docs:
7+
permissions:
8+
contents: write
89
runs-on: ubuntu-latest
910
steps:
10-
- uses: actions/checkout@v3
11-
with:
12-
ref: ${{ github.event.pull_request.head.ref }}
11+
- uses: actions/checkout@v4
1312

1413
- name: Setup Graphviz
1514
uses: ts-graphviz/setup-graphviz@v2
@@ -21,21 +20,25 @@ jobs:
2120
shell: bash
2221
working-directory: terraform/azure-devops/create-service-connection
2322

24-
- name: Render terraform docs and push changes back to PR
23+
- name: Render terraform docs
2524
uses: terraform-docs/gh-actions@main
2625
with:
2726
config-file: doc-gen/.terraform-docs.yml
2827
working-dir: terraform/azure-devops/create-service-connection
2928
output-format: markdown table
3029
git-push: false
3130

31+
- name: Fix .git permissions
32+
run: sudo chmod -R ugo+rwX .git
33+
3234
- name: Commit changes
3335
run: |
36+
git config user.name github-actions
37+
git config user.email github-actions@github.com
3438
git add graph.png
3539
git add README.md
36-
git config --local user.email ""
37-
git config --local user.name "GitHub Actions"
3840
git diff-index --quiet HEAD || git commit -m "Update docs"
3941
git push
42+
# git diff-index --quiet HEAD || (git add -A && git commit -m'[bot] update files' --allow-empty && git push -f)
4043
shell: bash
4144
working-directory: terraform/azure-devops/create-service-connection

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ This repo contains a few [PowerShell](https://github.com/PowerShell/PowerShell)
2626

2727
## Azure DevOps
2828

29+
- Manage Azure Service Connection with [Terraform](terraform/azure-devops/create-service-connection/README.md) to create Managed Identity, Federated Identity Credential, secret rotation and ITSM metadata
2930
- Configure Terraform [azuread](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs#authenticating-to-azure-active-directory)/[azurerm](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#authenticating-to-azure) provider `ARM_*` environment variables to use the [AzureCLI](https://learn.microsoft.com/azure/devops/pipelines/tasks/reference/azure-cli-v2?view=azure-pipelines) task [Service Connection](https://learn.microsoft.com/azure/devops/pipelines/library/connect-to-azure?view=azure-devops):
3031
[set_terraform_azurerm_vars.ps1](scripts/azure-devops/set_terraform_azurerm_vars.ps1)
3132
- Create Managed Identity for Service Connection with Workload identity federation: [create_azurerm_msi_oidc_service_connection.ps1](scripts/azure-devops/create_azurerm_msi_oidc_service_connection.ps1)
32-
- Create Managed Identity for Service Connection with Workload identity federation with [Terraform](terraform/azure-devops/create-service-connection/README.md)
3333
- List identities for Azure DevOps Service Connections in Entra ID pertaining to Azure DevOps organization and (optionally) project: [list_service_connection_identities.ps1](scripts/azure-devops/list_service_connection_identities.ps1)
3434
- List Azure DevOps Service Connections in an Azure DevOps organization and project: [list_service_connections.ps1](scripts/azure-devops/list_service_connections.ps1)
3535
- 'Pretty-name' Entra ID applications created for Service Connections, so the Service Connection name is included in the application display name: [rename_service_connection_applications.ps1](scripts/azure-devops/rename_service_connection_applications.ps1)

terraform/azure-devops/create-service-connection/README.md

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,74 @@
33

44
[![Build Status](https://dev.azure.com/geekzter/Pipeline%20Playground/_apis/build/status%2Fcreate-service-connection?branchName=main&label=terraform-ci)](https://dev.azure.com/geekzter/Pipeline%20Playground/_build/latest?definitionId=5&branchName=main)
55

6-
Many large customers have additional requirements around the management of the Entra ID object that a service connection creates and the permissions it is assigned to.
6+
Azure DevOps uses service connections to connect to services that are targets for cloud infrastructure provisioning and application deployment. The most commonly used service connection is the [Azure Resource Manager service connection](https://learn.microsoft.com/azure/devops/pipelines/library/connect-to-azure?view=azure-devops). This creates an object in Azure DevOps, an identity in Entra ID and a role assignment in Azure.
77

8-
These are a few common requirements and constraints:
8+
Many Enterprise customers have requirements around the management of Entra [workload identities](https://learn.microsoft.com/entra/workload-id/workload-identities-overview) (applications, service principals, managed identities) as well as the permissions they are assigned to.
99

10+
Here are a few common requirements and constraints:
11+
12+
- Creation of app registrations is [disabled in the Entra ID tenant](https://learn.microsoft.com/entra/identity/role-based-access-control/delegate-app-roles#restrict-who-can-create-applications) and/or
13+
the use of Managed Identities for Azure access is mandated
1014
- Specific secret expiration and auto-rotation control
11-
- Custom role assignments for Azure [data plane](https://learn.microsoft.com/azure/azure-resource-manager/management/control-plane-and-data-plane#data-plane) access e.g. [Key Vault](https://learn.microsoft.com/azure/key-vault/general/rbac-guide?tabs=azure-cli#azure-built-in-roles-for-key-vault-data-plane-operations), [Kusto](https://learn.microsoft.com/azure/data-explorer/kusto/access-control/role-based-access-control), [Storage](https://learn.microsoft.com/azure/storage/blobs/assign-azure-role-data-access?tabs=portal)
12-
- Creation of app registrations is [disabled in Entra ID](https://learn.microsoft.com/entra/identity/role-based-access-control/delegate-app-roles#restrict-who-can-create-applications) or the use of Managed Identities for Azure access is explicitly mandated
13-
- Required ITSM metadata on Entra ID app registration (IT Service Management Reference, naming convention, notes)
14-
- Co-owners are required to exist for Entra ID app registrations
15-
- The organization has an IT fulfillment process where identities are automatically created based on a service request
15+
- ITSM metadata is required on Entra ID objects (service nanagement reference, naming convention, notes)
16+
- Co-owners are required to exist for Entra ID apps
17+
- Custom role assignments are needed for Azure [data plane](https://learn.microsoft.com/azure/azure-resource-manager/management/control-plane-and-data-plane#data-plane) access e.g. [Key Vault](https://learn.microsoft.com/azure/key-vault/general/rbac-guide?tabs=azure-cli#azure-built-in-roles-for-key-vault-data-plane-operations), [Kusto](https://learn.microsoft.com/azure/data-explorer/kusto/access-control/role-based-access-control), [Storage](https://learn.microsoft.com/azure/storage/blobs/assign-azure-role-data-access?tabs=portal)
18+
- Access needs to be granted to multiple Azure subscriptions that are not part of the same management group
19+
- An IT fulfillment process exists where identities are automatically provisioned based on a service request
1620

1721
## Why Terraform?
1822

19-
Terraform employs a provider model which enable all changes to be made by a single tool and configuration:
23+
Terraform employs a provider model which enables all changes to be made by a single tool and configuration:
2024

2125
| Service | Provider | API |
2226
|--------------|----------|-----|
2327
| Azure | [azurerm](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) | [Azure Resource Manager REST API](https://learn.microsoft.com/rest/api/resources/) |
2428
| Azure DevOps | [azuredevops](https://registry.terraform.io/providers/microsoft/azuredevops/latest/docs) | [Azure DevOps REST API](https://learn.microsoft.com/rest/api/azure/devops/serviceendpoint/endpoints) |
2529
| Entra ID | [azuread](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs) | [Microsoft Graph API](https://learn.microsoft.com/graph/use-the-api) |
2630

27-
Terraform is a declarative tool that is capable if inferring dependencies to create resources in the correct order. This is the output from `terraform graph`:
31+
[HCL](https://developer.hashicorp.com/terraform/language#about-the-terraform-language), the language used, is declarative and the tool is capable if inferring dependencies to create resources in order. This is the output from `terraform graph`:
2832
![Terraform graph](graph.png)
2933

3034
More information:
3135

3236
- [Overview of Terraform on Azure - What is Terraform?](https://learn.microsoft.com/azure/developer/terraform/overview)
33-
- [Cloud Adoption Framework Infrastructure-as-Code CI/CD security guidance](https://learn.microsoft.com/azure/cloud-adoption-framework/secure/best-practices/secure-devops)
37+
- [Cloud Adoption Framework - Infrastructure-as-Code CI/CD security guidance](https://learn.microsoft.com/azure/cloud-adoption-framework/secure/best-practices/secure-devops)
3438

3539
## Provisioning
3640

37-
Provisioning is a matter of specifying [variables](https://developer.hashicorp.com/terraform/language/values/variables) (see [inputs](#input_azdo_organization_url) below) and running `terraform apply`. To understand how the Terraform configuration can be created in automation, review
41+
Provisioning is a matter of specifying Terraform [variables](https://developer.hashicorp.com/terraform/language/values/variables) (see [inputs](#inputs) below) and running `terraform apply`. To understand how the Terraform configuration can be created in automation, review
3842
[tf_create_azurerm_service_connection.ps1](../../../scripts/azure-devops/tf_create_azurerm_service_connection.ps1) and the
3943
[CI pipeline](azure-pipelines.yml).
4044

4145
### Examples
4246

4347
Terraform variable can be provided as a .auto.tfvars file, see [sample](config.auto.tfvars.sample).
4448

45-
#### App registration with Federated Credential and ITSM data
49+
#### Default configuration
50+
51+
This creates an App registration with Federated Identity Credential and `Contributor` role on the Azure subscription used by the Terraform `azurerm` provider.
52+
53+
```hcl
54+
azdo_organization_url = "https://dev.azure.com/my-organization"
55+
azdo_project_name = "my-project"
56+
```
57+
58+
Pre-requisites:
59+
60+
- The user can create app registrations i.e.:
61+
- Creation of app registrations is not [disabled in Entra ID](https://learn.microsoft.com/entra/identity/role-based-access-control/delegate-app-roles#restrict-who-can-create-applications);
62+
or
63+
- The user is member of a privileged Entra ID role e.g. [Application Developer](https://learn.microsoft.com/entra/identity/role-based-access-control/permissions-reference#application-developer)
64+
- The user is an owner of the Azure subscription (so role assignment can be performed)
65+
66+
#### Managed Identity with FIC and custom RBAC
67+
68+
This creates a Managed Identity with Federated Identity Credential and custom Azure RBAC (role-based access control) role assignments:
4669

4770
```hcl
4871
azdo_creates_identity = false
72+
azdo_organization_url = "https://dev.azure.com/my-organization"
73+
azdo_project_name = "my-project"
4974
azure_role_assignments = [
5075
{
5176
scope = "/subscriptions/00000000-0000-0000-0000-000000000000"
@@ -54,8 +79,28 @@ azure_role_assignments = [
5479
{
5580
scope = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg"
5681
role = "Storage Blob Data Contributor"
82+
},
83+
{
84+
scope = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg"
85+
role = "Key Vault Secrets User"
5786
}
5887
]
88+
create_federation = true
89+
create_managed_identity = true
90+
managed_identity_resource_group_id = "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/msi-rg"
91+
```
92+
93+
Pre-requisites:
94+
95+
- A resource group to hold the Managed Identity has been pre-created
96+
- The user is an owner of the Azure scopes to create role assignments on
97+
98+
#### App registration with FIC and ITSM metadata
99+
100+
This creates an Entra ID app registration with IT service reference and notes fields populated as well as specifying co-owners:
101+
102+
```hcl
103+
azdo_creates_identity = false
59104
azdo_organization_url = "https://dev.azure.com/my-organization"
60105
azdo_project_name = "my-project"
61106
create_federation = true
@@ -65,7 +110,17 @@ entra_app_owner_object_ids = ["00000000-0000-0000-0000-000000000000","111111
65110
entra_service_management_reference = "11111111-1111-1111-1111-111111111111"
66111
```
67112

68-
#### App registration with short-lived secret
113+
Pre-requisites:
114+
115+
- The user can create app registrations i.e.:
116+
- Creation of app registrations is not [disabled in Entra ID](https://learn.microsoft.com/entra/identity/role-based-access-control/delegate-app-roles#restrict-who-can-create-applications);
117+
or
118+
- The user is member of a privileged Entra ID role e.g. [Application Developer](https://learn.microsoft.com/entra/identity/role-based-access-control/permissions-reference#application-developer)
119+
- The user is an owner of the Azure subscription (so role assignment can be performed)
120+
121+
#### App registration with short-lived secret and constrained RBAC
122+
123+
This creates an Entra ID app registration with secret that expires after 1 hour:
69124

70125
```hcl
71126
azdo_creates_identity = false
@@ -81,30 +136,17 @@ create_federation = false
81136
create_managed_identity = false
82137
entra_secret_expiration_days = 0 # secret lasts 1 hour
83138
```
139+
Pre-requisites:
84140

85-
#### Managed Identity with Federated Credential
86-
87-
```hcl
88-
azdo_creates_identity = false
89-
azdo_organization_url = "https://dev.azure.com/my-organization"
90-
azdo_project_name = "my-project"
91-
azure_role_assignments = [
92-
{
93-
scope = "/subscriptions/00000000-0000-0000-0000-000000000000"
94-
role = "Contributor"
95-
},
96-
{
97-
scope = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg"
98-
role = "Key Vault Secrets User"
99-
}
100-
]
101-
create_federation = true
102-
create_managed_identity = true
103-
managed_identity_resource_group_id = "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/msi-rg"
104-
```
141+
- The user can create app registrations i.e.:
142+
- Creation of app registrations is not [disabled in Entra ID](https://learn.microsoft.com/entra/identity/role-based-access-control/delegate-app-roles#restrict-who-can-create-applications);
143+
or
144+
- The user is member of a privileged Entra ID role e.g. [Application Developer](https://learn.microsoft.com/entra/identity/role-based-access-control/permissions-reference#application-developer)
145+
- The user is an owner of the Azure resource group (so role assignment can be performed)
105146

106147
## Terraform Configuration
107148

149+
The (required) variables and output are listed below. Sensitive outputs are masked by default.
108150
Generated with [terraform-docs](https://terraform-docs.io/).
109151

110152
### Providers
@@ -134,7 +176,7 @@ Generated with [terraform-docs](https://terraform-docs.io/).
134176
| <a name="input_azdo_creates_identity"></a> [azdo_creates_identity](#input_azdo_creates_identity) | Let Azure DevOps create identity for service connection | `bool` | `false` | no |
135177
| <a name="input_azure_role_assignments"></a> [azure_role_assignments](#input_azure_role_assignments) | Role assignments to create for the service connection's identity. If this is empty, the Contributor role will be assigned on the azurerm provider subscription. | `set(object({scope=string, role=string}))` | `[]` | no |
136178
| <a name="input_create_federation"></a> [create_federation](#input_create_federation) | Use workload identity federation instead of a App Registration secret | `bool` | `true` | no |
137-
| <a name="input_create_managed_identity"></a> [create_managed_identity](#input_create_managed_identity) | Creates a Managed Identity instead of a App Registration | `bool` | `true` | no |
179+
| <a name="input_create_managed_identity"></a> [create_managed_identity](#input_create_managed_identity) | Creates a Managed Identity instead of a App Registration | `bool` | `false` | no |
138180
| <a name="input_entra_app_notes"></a> [entra_app_notes](#input_entra_app_notes) | Description to put in the Entra ID app registration notes field | `string` | `null` | no |
139181
| <a name="input_entra_app_owner_object_ids"></a> [entra_app_owner_object_ids](#input_entra_app_owner_object_ids) | Object ids of the users that will be co-owners of the Entra ID app registration | `list(string)` | `null` | no |
140182
| <a name="input_entra_secret_expiration_days"></a> [entra_secret_expiration_days](#input_entra_secret_expiration_days) | Secret expiration in days | `number` | `90` | no |

0 commit comments

Comments
 (0)