Skip to content

Commit 9d595fd

Browse files
authored
Terraform README (#56)
* Add descriptions to inputs & outputs * Use terraform-docs * Generate docs * Add workflow to generate README * Add diagram
1 parent a59ea46 commit 9d595fd

File tree

11 files changed

+314
-15
lines changed

11 files changed

+314
-15
lines changed

.github/workflows/docs.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Generate terraform docs
2+
on:
3+
- pull_request
4+
- push
5+
6+
jobs:
7+
docs:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v3
11+
with:
12+
ref: ${{ github.event.pull_request.head.ref }}
13+
14+
- name: Setup Graphviz
15+
uses: ts-graphviz/setup-graphviz@v2
16+
17+
- name: Generate diagram
18+
run: |
19+
terraform init
20+
terraform graph | dot -Tpng >graph.png
21+
git push
22+
shell: bash
23+
working-directory: terraform/azure-devops/create-service-connection
24+
25+
- name: Render terraform docs and push changes back to PR
26+
uses: terraform-docs/gh-actions@main
27+
with:
28+
working-dir: terraform/azure-devops/create-service-connection
29+
output-file: README.md
30+
output-method: inject
31+
git-push: "true"

Brewfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ cask "powershell"
44

55
brew "azure-cli"
66
brew "gh"
7-
brew "terraform"
7+
brew "graphviz"
8+
brew "terraform"
9+
brew "terraform-docs"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ This repo contains a few [PowerShell](https://github.com/PowerShell/PowerShell)
2929
- 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):
3030
[set_terraform_azurerm_vars.ps1](scripts/azure-devops/set_terraform_azurerm_vars.ps1)
3131
- 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)
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)
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# # see: https://terraform-docs.io/user-guide/configuration/version
2+
# version: ">= 0.10, < 0.12"
3+
4+
# see: https://terraform-docs.io/user-guide/configuration/formatter
5+
formatter: markdown table
6+
7+
# see: https://terraform-docs.io/user-guide/configuration/header-from
8+
header-from: doc-gen/header.md
9+
10+
# see: https://terraform-docs.io/user-guide/configuration/footer-from
11+
footer-from: doc-gen/footer.md
12+
13+
# see: https://terraform-docs.io/user-guide/configuration/recursive
14+
# recursive:
15+
# enabled: false
16+
# path: modules
17+
18+
# see: https://terraform-docs.io/user-guide/configuration/sections
19+
sections:
20+
show:
21+
- header
22+
- inputs
23+
- providers
24+
- modules
25+
- outputs
26+
- footer
27+
28+
# # see: https://terraform-docs.io/user-guide/configuration/content
29+
# content: |-
30+
# Any arbitrary text can be placed anywhere in the content
31+
#
32+
# {{ .Header }}
33+
#
34+
# and even in between sections. also spaces will be preserved:
35+
#
36+
# - item 1
37+
# - item 1-1
38+
# - item 1-2
39+
# - item 2
40+
# - item 3
41+
#
42+
# ## Resources
43+
# {{ range .Module.Resources }}
44+
# - {{ .GetMode }}.{{ .Spec }} ({{ .Position.Filename }}#{{ .Position.Line }})
45+
# {{- end }}
46+
#
47+
# ## Examples
48+
#
49+
# ```hcl
50+
# {{ include "relative/path/to/main.tf" }}
51+
# ```
52+
#
53+
# {{ .Providers }}
54+
#
55+
# and they don't even need to be in the default order
56+
#
57+
# {{ .Outputs }}
58+
#
59+
# {{ .Inputs }}
60+
61+
# # see: https://terraform-docs.io/user-guide/configuration/output
62+
# output:
63+
# file: README.md
64+
# mode: inject
65+
# template: |-
66+
# <!-- BEGIN_TF_DOCS -->
67+
# The template can be customized with aribitrary markdown content.
68+
# For example this can be shown before the actual content generated
69+
# by formatters.
70+
#
71+
# {{ .Content }}
72+
#
73+
# You can also show something after it!
74+
# <!-- END_TF_DOCS -->
75+
76+
# see: https://terraform-docs.io/user-guide/configuration/sort
77+
sort:
78+
enabled: true
79+
by: required
80+
81+
# # https://terraform-docs.io/user-guide/configuration/output-values/
82+
# output-values:
83+
# enabled: false
84+
# from: ""
85+
86+
# see: https://terraform-docs.io/user-guide/configuration/settings
87+
settings:
88+
indent: 4
89+
escape: false
90+
default: false
91+
required: false
92+
type: true

terraform/azure-devops/create-service-connection/.terraform.lock.hcl

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<!-- BEGIN_TF_DOCS -->
2+
# Terraform managed Azure Service Connection
3+
4+
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.
5+
6+
These are a few common requirements and constraints:
7+
8+
- Specific secret expiration and auto-rotation control
9+
- 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)
10+
- 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
11+
- Required ITSM metadata on Entra ID app registration (IT Service Management Reference, naming convention, notes)
12+
- Co-owners are required to exist for Entra ID app registrations
13+
- The organization has an IT fulfillment process where identities are automatically created based on a service request
14+
15+
Terraform employs a provider model which enable all changes to be made by a single tool and configuration:
16+
17+
| Service | Provider | API |
18+
|--------------|----------|-----|
19+
| Azure | [azurerm](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) | [Azure Resource Manager REST API](https://learn.microsoft.com/rest/api/resources/) |
20+
| 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) |
21+
| Entra ID | [azuread](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs) | [Microsoft Graph API](https://learn.microsoft.com/graph/use-the-api) |
22+
23+
## Provisioning
24+
25+
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`:
26+
![Terraform graph](graph.png)
27+
28+
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`.
29+
30+
- To understand how the Terraform configuration can be created in automation, review
31+
[tf_create_azurerm_service_connection.ps1](../../../scripts/azure-devops/tf_create_azurerm_service_connection.ps1) and the
32+
[CI pipeline](azure-pipelines.yml).
33+
- For more information on using Terraform with Azure and other Microsoft services, see [Overview of Terraform on Azure - What is Terraform?](https://learn.microsoft.com/azure/developer/terraform/overview)
34+
- For infrastructure-as-code best practices, review [Securing the pipeline and CI/CD workflow](https://learn.microsoft.com/azure/cloud-adoption-framework/secure/best-practices/secure-devops).
35+
36+
## Terraform Configuration
37+
38+
## Providers
39+
40+
| Name | Version |
41+
|------|---------|
42+
| <a name="provider_azurerm"></a> [azurerm](#provider_azurerm) | 3.99.0 |
43+
| <a name="provider_external"></a> [external](#provider_external) | 2.3.3 |
44+
| <a name="provider_random"></a> [random](#provider_random) | 3.6.0 |
45+
| <a name="provider_terraform"></a> [terraform](#provider_terraform) | n/a |
46+
47+
## Modules
48+
49+
| Name | Source | Version |
50+
|------|--------|---------|
51+
| <a name="module_azure_access"></a> [azure_access](#module_azure_access) | ./modules/azure-access | n/a |
52+
| <a name="module_azure_role_assignments"></a> [azure_role_assignments](#module_azure_role_assignments) | ./modules/azure-access | n/a |
53+
| <a name="module_entra_app"></a> [entra_app](#module_entra_app) | ./modules/app-registration | n/a |
54+
| <a name="module_managed_identity"></a> [managed_identity](#module_managed_identity) | ./modules/managed-identity | n/a |
55+
| <a name="module_service_connection"></a> [service_connection](#module_service_connection) | ./modules/service-connection | n/a |
56+
57+
## Inputs
58+
59+
| Name | Description | Type |
60+
|------|-------------|------|
61+
| <a name="input_azdo_organization_url"></a> [azdo_organization_url](#input_azdo_organization_url) | The Azure DevOps organization URL (e.g. https://dev.azure.com/contoso) | `string` |
62+
| <a name="input_azdo_project_name"></a> [azdo_project_name](#input_azdo_project_name) | The Azure DevOps project name to create the service connection in | `string` |
63+
| <a name="input_azdo_creates_identity"></a> [azdo_creates_identity](#input_azdo_creates_identity) | Let Azure DevOps create identity for service connection | `bool` |
64+
| <a name="input_azure_role"></a> [azure_role](#input_azure_role) | The Azure RBAC role to assign to the service connection's identity | `string` |
65+
| <a name="input_azure_role_assignments"></a> [azure_role_assignments](#input_azure_role_assignments) | Additional role assignments to create for the service connection's identity | `set(object({scope=string, role=string}))` |
66+
| <a name="input_azure_scope"></a> [azure_scope](#input_azure_scope) | The Azure scope to assign access to | `string` |
67+
| <a name="input_create_federation"></a> [create_federation](#input_create_federation) | Use workload identity federation instead of a App Registration secret | `bool` |
68+
| <a name="input_create_managed_identity"></a> [create_managed_identity](#input_create_managed_identity) | Creates a Managed Identity instead of a App Registration | `bool` |
69+
| <a name="input_entra_owner_object_ids"></a> [entra_owner_object_ids](#input_entra_owner_object_ids) | Object ids of the users that will be co-owners of the Entra ID app registration | `list(string)` |
70+
| <a name="input_entra_secret_expiration_days"></a> [entra_secret_expiration_days](#input_entra_secret_expiration_days) | Secret expiration in days | `number` |
71+
| <a name="input_entra_service_management_reference"></a> [entra_service_management_reference](#input_entra_service_management_reference) | IT Service Management Reference to add to the App Registration | `string` |
72+
| <a name="input_managed_identity_resource_group_id"></a> [managed_identity_resource_group_id](#input_managed_identity_resource_group_id) | The resource group to create the Managed Identity in | `string` |
73+
| <a name="input_resource_prefix"></a> [resource_prefix](#input_resource_prefix) | The prefix to put in front of resource names created | `string` |
74+
| <a name="input_resource_suffix"></a> [resource_suffix](#input_resource_suffix) | The suffix to append to resource names created | `string` |
75+
| <a name="input_run_id"></a> [run_id](#input_run_id) | The ID that identifies the pipeline / workflow that invoked Terraform (used in CI/CD) | `number` |
76+
77+
## Outputs
78+
79+
| Name | Description |
80+
|------|-------------|
81+
| <a name="output_azdo_project_id"></a> [azdo_project_id](#output_azdo_project_id) | The Azure DevOps project id the service connection was created in |
82+
| <a name="output_azdo_service_connection_id"></a> [azdo_service_connection_id](#output_azdo_service_connection_id) | The Azure DevOps service connection id |
83+
| <a name="output_azdo_service_connection_name"></a> [azdo_service_connection_name](#output_azdo_service_connection_name) | The Azure DevOps service connection name |
84+
| <a name="output_azdo_service_connection_url"></a> [azdo_service_connection_url](#output_azdo_service_connection_url) | The Azure DevOps service connection portal URL |
85+
| <a name="output_azure_resource_group_name"></a> [azure_resource_group_name](#output_azure_resource_group_name) | The name of the resource group the service connection was granted access to |
86+
| <a name="output_azure_scope"></a> [azure_scope](#output_azure_scope) | The Azure scope the service connection was granted access to |
87+
| <a name="output_azure_scope_url"></a> [azure_scope_url](#output_azure_scope_url) | The Azure scope portal URL the service connection was granted access to |
88+
| <a name="output_azure_subscription_id"></a> [azure_subscription_id](#output_azure_subscription_id) | The Azure subscription id the service connection was granted access to |
89+
| <a name="output_azure_subscription_name"></a> [azure_subscription_name](#output_azure_subscription_name) | The Azure subscription name the service connection was granted access to |
90+
| <a name="output_identity_application_id"></a> [identity_application_id](#output_identity_application_id) | The app/client id of the service connection's identity |
91+
| <a name="output_identity_application_name"></a> [identity_application_name](#output_identity_application_name) | The name of the service connection's identity |
92+
| <a name="output_identity_federation_subject"></a> [identity_federation_subject](#output_identity_federation_subject) | The federation subject |
93+
| <a name="output_identity_issuer"></a> [identity_issuer](#output_identity_issuer) | The federation issuer |
94+
| <a name="output_identity_object_id"></a> [identity_object_id](#output_identity_object_id) | The object id of the service connection's identity |
95+
| <a name="output_identity_principal_id"></a> [identity_principal_id](#output_identity_principal_id) | The service principal id of the service connection's identity |
96+
| <a name="output_identity_principal_name"></a> [identity_principal_name](#output_identity_principal_name) | The service principal name of the service connection's identity |
97+
| <a name="output_identity_principal_url"></a> [identity_principal_url](#output_identity_principal_url) | The service principal portal url of the service connection's identity |
98+
| <a name="output_identity_secret"></a> [identity_secret](#output_identity_secret) | The secret of the service connection's identity |
99+
| <a name="output_identity_secret_end_date"></a> [identity_secret_end_date](#output_identity_secret_end_date) | The secret expiration date of the service connection's identity |
100+
| <a name="output_identity_url"></a> [identity_url](#output_identity_url) | The portal url of the service connection's identity |
101+
<!-- END_TF_DOCS -->

terraform/azure-devops/create-service-connection/doc-gen/footer.md

Whitespace-only changes.

0 commit comments

Comments
 (0)