用 Owner 权限跑 Terraform 等於用 root 权限跑後端,夜路跑多了迟早遇到鬼
CI/CD 系列
课程内容与代码会放在 Github 上: https://github.com/chechiachang/terraform-30-days
赛後文章会整理放到个人的部落格上 http://chechia.net/
本章介绍如何建立独立的 service principal (service account / iam role) 专门给 terraform 执行。
前面的例子,我们执行 Terraform 都是用 azure ad User 的身份执行。
Review: 我们使用 az-cli az login,让 terraform 使用本地的 credential 档案。也就是说 terraform 是使用 login user 的权限来运行。我们可以检查一下目前使用者的 Azure 权限
az role assignment list --include-inherited --assignee 12345678-1234-1234-1234-123456789012
[
{
"principalName": "chechia_chechia.net#EXT#@chechianet.onmicrosoft.com",
"principalType": "User",
"roleDefinitionName": "User Access Administrator",
"scope": "/",
"type": "Microsoft.Authorization/roleAssignments"
}
]
Azure AD 的权限则需要通过 Azure portal 查看
Global administrator 基本上是超级管理员,权限其实蛮大的,Terraform 的操作并不需要这麽大的权限。
Linux 管理常说,没必要不要使用 root 的权限。
Terraform 也是同样道理。没事不要开着权限很大的帐号乱逛。
administrator / owner 权限太大,什麽事都能做很方便。但实务上常常使用 Admin role 其实是有相当风险的,使用 administrator role 操作 Terraform ,违反最小授权原则(POLP: Principle of least privilege)
所有 credential 只要使用,就可能有泄漏或被害的风险,只是管理方式不同,风险高低差异
我们上堂课展示过 CI / CD
通常 iam / RBAC 管理的权限,与其他 resource provision 的权限会切开,特别管理,连工程师的 User 都不应该有 iam 管理权限
许多整合性的角色权限 administrator, owner, editor, collaborater, ... 之类的权限其实都太大,最佳实践是用到什麽权限,就开什麽权限
NOTE:
在实务上,我们为 terraform 设定专属的 service principal。
我们会需要产生 terraform 专属的 service principal
登入认证使用非对称加密的 rsa key/crt,远比起传统密码更加安全
KEY_NAME=~/.ssh/terraform-30-days
openssl req -newkey rsa:4096 -nodes -subj '/CN=terraform-30-days' -keyout ${KEY_NAME}.key -out ${KEY_NAME}.csr
openssl x509 -signkey ${KEY_NAME}.key -in ${KEY_NAME}.csr -req -days 365 -out ${KEY_NAME}.crt
openssl pkcs12 -export -out ${KEY_NAME}.pfx -inkey ${KEY_NAME}.key -in ${KEY_NAME}.crt
Getting Private key
Enter Export Password:
Verifying - Enter Export Password:
ls ~/.ssh/terraform-30-days*
/Users/che-chia/.ssh/terraform-30-days.crt
/Users/che-chia/.ssh/terraform-30-days.csr
/Users/che-chia/.ssh/terraform-30-days.key
/Users/che-chia/.ssh/terraform-30-days.pfx
产生完後我们使用 terraform 来创建 azure service principal。这里还是使用有 admin 权限的 User 帐号来操作 terraform,范例在 azure/foundation/servcie_principal
,看一下内容
enable_service_principal_certificate=true
使用 certificate 来认证
# azure/foundation/service_principal
service_principal_name = "terraform-30-days"
enable_service_principal_certificate = true
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_certificate)
certificate_path = "/Users/che-chia/.ssh/terraform-30-days.crt"
password_rotation_in_years = 1
# Adding roles to service principal
# The principle of least privilege
role_definition_names = [
"Contributor"
]
这里参考 Github kumarvna/terraform-azuread-service-principal 来修改的是 repo 内的 module。module 本身有放上 Terraform Registry 所以可以直接使用,我自己调整内容所以放到本 repo。细节可以看 azure/modules/azuread_service_principal
确定没问题後 provision resource
terragrunt init
terragrunt plan
terragrunt apply
Azure 上就会产生 service principal,使用 certificate 做登入认证
测试一下 az-cli 是否能够登入 service principal,Azure 官方文件:Service Principal
cat ~/.ssh/terraform-30-days.key > ~/.ssh/terraform-30-days.keycrt
cat ~/.ssh/terraform-30-days.crt >> ~/.ssh/terraform-30-days.keycrt
APP_NAME=terraform-30-days
az ad sp list --display-name ${APP_NAME}
TENANT_ID=$(az ad sp list --display-name ${APP_NAME} | jq -r '.[0].appOwnerTenantId')
SERVICE_NAME=$(az ad sp list --display-name ${APP_NAME} | jq -r '.[0].servicePrincipalNames[0]')
az login --service-principal \
--username ${SERVICE_NAME} \
--tenant ${TENANT_ID} \
--password ~/.ssh/terraform-30-days.keycrt > /tmp/azure-login-profile
[
{
"cloudName": "AzureCloud",
"homeTenantId": "12345678-1234-1234-1234-123456789012",
"id": "12345678-1234-1234-1234-123456789012",
"isDefault": true,
"managedByTenants": [],
"name": "Microsoft Azure Sponsorship",
"state": "Enabled",
"tenantId": "12345678-1234-1234-1234-123456789012",
"user": {
"name": "12345678-1234-1234-1234-123456789012",
"type": "servicePrincipal"
}
}
]
目前身份是 service principal,检查一下自身权限 role assignment,看见正确设定的 role: Contributor
az role assignment list
[
{
"principalType": "ServicePrincipal",
...
"roleDefinitionName": "Contributor",
...
}
]
接下来要设定 terraform
有两个方法
这边示范使用环境变数,之後夹到 Github Action 上,或是其他 CI 上会比较方便,不用再更改 provider.tf 的原始码
export ARM_CLIENT_ID="00000000-0000-0000-0000-000000000000"
export ARM_CLIENT_CERTIFICATE_PATH="/Users/che-chia/.ssh/terraform-30-days.pfx"
export ARM_CLIENT_CERTIFICATE_PASSWORD=<password> # change this
export ARM_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
export ARM_TENANT_ID="00000000-0000-0000-0000-000000000000"
export ARM_CLIENT_ID=$(cat /tmp/azure-login-profile | jq -r '.[0].user.name')
export ARM_CLIENT_CERTIFICATE_PATH="/Users/che-chia/.ssh/terraform-30-days.pfx"
export ARM_CLIENT_CERTIFICATE_PASSWORD=<password> # change this
export ARM_SUBSCRIPTION_ID=$(az account subscription list | jq -r '.[0].subscriptionId')
export ARM_TENANT_ID=$(cat /tmp/azure-login-profile | jq -r '.[0].tenantId')
env | grep ARM
ARM_CLIENT_CERTIFICATE_PATH=/Users/che-chia/.ssh/terraform-30-days.pfx
ARM_CLIENT_ID=
ARM_SUBSCRIPTION_ID=
ARM_TENANT_ID=
ARM_CLIENT_CERTIFICATE_PASSWORD=
如果参数都正常,
terragrunt init && terragrunt plan
尝试更改自己 service principal 的 role,看能不能 Privilege escalation,把自己从 Contributor 变成 Owner。如果可以的话,terraform 可以自己提升权限变成 Owner,然後近来 azure 乱改
# azure/foundation/service_principal
role_definition_names = [
"Contributor",
"Owner" # try Privilege escalation
]
然後再次 apply 看看计谋会不会得逞
terragrunt plan
terragrunt apply
│ Error: Could not set Owners
│
│ with azuread_application.main,
│ on application.tf line 4, in resource "azuread_application" "main":
│ 4: owners = [data.azuread_client_config.current.object_id]
│ Error: authorization.RoleAssignmentsClient#Create: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationFailed" Message="The client '12345678-1234-1234-1234-123456789012' with object id '12345678-1234-1234-1234-123456789012' does not have authorization to perform action 'Microsoft.Authorization/roleAssignments/write' over scope '/subscriptions/ba8eb346-d19e-4f65-96d9-8c783e6eea61' or the scope is invalid. If access was recently granted, please refresh your credentials."
Plan 都正常,表示 read / refresh azure 上的资源时,service principal 的 contributor 全县市足够的
apply 则回传 403 permission denied 以及相关错误讯息,azure 表示 terraform 的 service principal 没有权限可以调整 RBAC。表示 service principal 权限是受到限制的,符合我们的预期。
之後 Terraform 的操作,我们就不再使用 az login 来产生本地的 credential,而是使用 service principal
# azure/provider
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
features {}
}
EOF
}
但是拜托
密码跟 certificate .key .pfx 拜托拜托不要 commit 到 git 里面,务必每次手动输入
密码跟 certificate .key .pfx 拜托拜托不要 commit 到 git 里面,务必每次手动输入
密码跟 certificate .key .pfx 拜托拜托不要 commit 到 git 里面,务必每次手动输入
很重要所以讲三次,但还是会看到有人 git add 就把 password commit 进去
使用 GitHub Actions 可以让 GitHub Repo 内自订且自动执行你的软件开发流程...
今天我们就利用我们之前所学的来做一个和旅游相关的Onboarding介面,事不宜迟赶快开始吧! 我想...
#733 - Flood Fill 连结: https://leetcode.com/proble...
由於 UI Flow 一定程度上已经交代了操作流程会走过哪些页面,接下来设计师就可以根据 UI F...
getInitialProps 是较为老旧的 API Next.js 9.3 版本後,官方释出了两个...