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

Initial terraform scripts for azure cncf subscription #6925

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions infra/azure/terraform/README.md
ritikaguptams marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# infra/azure/terraform
Terraform scripts and documentation for Cluster API for Azure ([CAPZ](https://github.com/kubernetes-sigs/cluster-api-provider-azure/tree/main/templates)) infrastructure that the Kubernetes community runs on Azure.
The terraform folder structure looks like this:
- capz
- cleanup-app
63 changes: 63 additions & 0 deletions infra/azure/terraform/capz/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Getting Started Guide for CAPZ resource management

# azure/terraform/capz
The CAPZ folder structure looks like this:
main.tf
├── resource_group
├── identities
├── key_vault
├── container_registry
├── storage_account
├── role_assignments
├── variables

# Prerequiste
The `az-cli-prow` service principal with federated credentials must be created by a tenant admin. The [iam-config/gce-param.json](./iam-config/gce-param.json) and [iam-config/eks-param.json](./iam-config/eks-param.json) files can be used for creating the federated credentials for GCE and EKS. Below is an example of how to add a federated credential.

```sh
az ad sp create-for-rbac --name az-cli-prow
appid=$(az ad sp list --filter "displayName eq 'az-cli-prow'" --query [0].appId --output tsv)
az ad app federated-credential create --id $appid --parameters param.json
```

The service principal needs the below mentioned role assignments, which gets taken care of by [role-assignments/main.tf](.role-assignments/main.tf):
- Contributor role access to the sub.
- Creation of a custom role to give write access
- acrpush role for the registry
- Storage Blob Data Contributor role for Storage account

Note: To assign Contributor access, the person running this script needs to be a contributor on the Azure subscription. If you are not, reach out to someone who is and ask them to manually run the below command and comment out that bit of code from [role-assignments/main.tf](.role-assignments/main.tf).

```sh
objectid=$(az ad sp list --filter "displayName eq 'az-cli-prow'" --query [0].id --output tsv)
az role assignment create --assignee-object-id $(objectid) --assignee-principal-type ServicePrincipal --role Contributor --scope /subscriptions/<subid>
```

# Terraform State Management

We use an Azure backend to maintain the Terraform state and enable collaboration on the infrastructure resources created.
We use the following values to store and manage the state:

- **Resource Group Name:** `terraform-states-azure`
- **Storage Account Name:** `terraformstatescomm`
- **Container Name:** `tfstate`
- **Key:** `terraform.tfstate`

## To Apply Terraform

Note: The first ever run will take a bit (about 20 minutes) to register the Container Service and Kubernetes Configuration providers while running `main.tf`. Get up and stretch your legs while it wires everything up. The next reapplications of terraform scripts will be a lot faster as terraform does not re-register providers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚶


1. Initialize Terraform:
```bash
terraform init
```

2. Plan the Terraform deployment and output it to a file:
```bash
terraform plan -out main.tfplan
```

3. Apply the planned Terraform deployment:
```bash
terraform apply ./main.tfplan
```
109 changes: 109 additions & 0 deletions infra/azure/terraform/capz/container-registry/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
Copyright 2024 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

variable "resource_group_name" {
type = string
}

variable "location" {
type = string
}

resource "azurerm_container_registry" "capzci_registry" {
name = "capzcicommunity"
location = var.location
resource_group_name = var.resource_group_name
sku = "Premium"
anonymous_pull_enabled = true

retention_policy {
days = 7
enabled = true
}

tags = {
RetentionPolicy = "7days"
}
}

resource "azurerm_management_lock" "registry_lock" {
name = "DO-NOT_DELETE"
scope = azurerm_container_registry.capzci_registry.id
lock_level = "CanNotDelete"
notes = "Contact Capz"
}

resource "azurerm_container_registry_task" "registry_task" {
container_registry_id = azurerm_container_registry.capzci_registry.id
name = "midnight_capz_purge"
agent_setting {
cpu = 2
}
base_image_trigger {
name = "defaultBaseimageTriggerName"
type = "Runtime"
update_trigger_payload_type = "Default"
}
encoded_step {
task_content = base64encode(<<EOF
version: v1.1.0
steps:
- cmd: acr purge --filter azdisk:* --filter azure-cloud-controller-manager:* --filter azure-cloud-node-manager-arm64:* --filter azure-cloud-node-manager:* --filter cluster-api-azure:* --ago 1d --untagged
disableWorkingDirectoryOverride: true
timeout: 3600
EOF
)
}
platform {
architecture = "amd64"
os = "Linux"
}
timer_trigger {
name = "t1"
schedule = "0 0 * * *"
}
}

output "container_registry_id" {
value = azurerm_container_registry.capzci_registry.id
}

resource "azurerm_container_registry" "e2eprivate_registry" {
name = "e2eprivatecommunity"
location = var.location
resource_group_name = var.resource_group_name
sku = "Premium"

retention_policy {
days = 7
enabled = true
}

tags = {
RetentionPolicy = "7days"
}
}

resource "azurerm_management_lock" "e2eregistry_lock" {
name = "DO-NOT_DELETE"
scope = azurerm_container_registry.e2eprivate_registry.id
lock_level = "CanNotDelete"
notes = "Contact Capz"
}

output "e2eprivate_registry_id" {
value = azurerm_container_registry.e2eprivate_registry.id
}
8 changes: 8 additions & 0 deletions infra/azure/terraform/capz/iam-config/eks-param.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "prow-eks-identity-credential",
"issuer": "https://oidc.eks.us-east-2.amazonaws.com/id/F8B73554FE6FBAF9B19569183FB39762",
"subject": "system:serviceaccount:test-pods:default",
"audiences": [
"api://AzureADTokenExchange"
]
}
8 changes: 8 additions & 0 deletions infra/azure/terraform/capz/iam-config/gce-param.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "prow-gce-identity-credential",
"issuer": "https://container.googleapis.com/v1/projects/k8s-infra-prow-build/locations/us-central1/clusters/prow-build",
"subject": "system:serviceaccount:test-pods:default",
"audiences": [
"api://AzureADTokenExchange"
]
}
53 changes: 53 additions & 0 deletions infra/azure/terraform/capz/identities/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2024 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

variable "resource_group_name" {
type = string
}

variable "location" {
type = string
}

resource "azurerm_user_assigned_identity" "cloud_provider_user_identity" {
name = "cloud-provider-user-identity"
location = var.location
resource_group_name = var.resource_group_name
}

resource "azurerm_user_assigned_identity" "domain_vm_identity" {
name = "domain-vm-identity"
location = var.location
resource_group_name = var.resource_group_name
}

resource "azurerm_user_assigned_identity" "gmsa_user_identity" {
name = "gmsa-user-identity"
location = var.location
resource_group_name = var.resource_group_name
}

output "cloud_provider_user_identity_id" {
value = azurerm_user_assigned_identity.cloud_provider_user_identity.principal_id
}

output "domain_vm_identity_id" {
value = azurerm_user_assigned_identity.domain_vm_identity.principal_id
}

output "gmsa_user_identity_id" {
value = azurerm_user_assigned_identity.gmsa_user_identity.principal_id
}
64 changes: 64 additions & 0 deletions infra/azure/terraform/capz/key-vault/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2024 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

variable "resource_group_name" {
type = string
}

variable "location" {
type = string
}

variable "tenant_id" {
type = string
}

variable "identities" {
type = object({
domain_vm_identity_id = string
gmsa_user_identity_id = string
})
}

resource "azurerm_key_vault" "capz_ci_gmsa" {
name = "capz-ci-gmsa-community"
location = var.location
resource_group_name = var.resource_group_name
tenant_id = var.tenant_id
sku_name = "standard"
}

resource "azurerm_key_vault_access_policy" "access_policy_domain_vm_identity" {
key_vault_id = azurerm_key_vault.capz_ci_gmsa.id
tenant_id = var.tenant_id
object_id = var.identities.domain_vm_identity_id
secret_permissions = [
"Set"
]
}

resource "azurerm_key_vault_access_policy" "access_policy_gmsa_user_identity" {
key_vault_id = azurerm_key_vault.capz_ci_gmsa.id
tenant_id = var.tenant_id
object_id = var.identities.gmsa_user_identity_id
secret_permissions = [
"Get"
]
}

output "key_vault_id" {
value = azurerm_key_vault.capz_ci_gmsa.id
}
Loading