Terraform 身份認證
本文詳細介紹阿里云 Terraform Provider 的身份認證方式。
概述
Terraform 身份認證是指對使用到的 Terraform 提供商插件的身份認證,即在通過 Terraform 操作阿里云基礎設施前對阿里云 Terraform Provider 的身份認證,只有認證通過后才能與阿里云 API 進行通信并創建和管理阿里云的基礎設施資源。
阿里云 Terraform Provider 的身份認證方式有很多種,選擇不同的認證方式一方面依賴于 Terraform 安裝和運行所在的環境,另一方面取決于您的使用場景。
認證方式 | 使用說明 | 適用場景 |
靜態配置 (access_key) | 將 AK 以明文的方式定義在配置文件中或者通過參數傳入的方式進行設置 | 開發環境測試驗證; CI/CD 資源管理流程 |
環境變量 (ALIBABA_CLOUD_ACCESS_KEY) | 將 AK 信息保存為環境變量,在沒有靜態配置的情況下,從環境變量中讀取 | 開發環境測試驗證; 獨立的運行環境,如 ECS |
ECS 服務角色 (ecs_role_name) | 從 ECS 實例的 Meta 中獲取綁定到這個實例上的 RAM 角色對應的訪問憑證 | Terraform 運行在 ECS 實例中 |
角色扮演 (assume_role) | 通過角色扮演的方式換取訪問憑證 | 多賬號資源管理; CI/CD 資源管理流程 |
OIDC 角色扮演(assume_role_with_oidc) | 通過 OIDC 角色扮演的方式換取訪問憑證 | Terraform 運行在阿里云 Kubernetes 集群中 |
共享的配置文件 (profile) | 將如上認證方式通過阿里云 CLI 配置到統一的文件中,通過指定 profile 的名稱來獲取訪問憑證 | 多賬號,多地域資源管理; 開發環境測試驗證 多環境資源管理 |
認證方式
接下來將詳細介紹不同認證方式的用法。
靜態配置
靜態配置是指直接在 Terraform 配置文件的 provider 代碼塊中定義訪問憑證,如下所示:
provider "alicloud" {
access_key = "<你的 Access Key ID>"
secret_key = "<你的 Access Key Secret>"
# 如果是 STS 的訪問憑證,此處需要配置 security_token
# security_token = "<你的 STS Token>"
}
為了安全起見,推薦以變量的方式傳入訪問憑證,而非直接以明文的方式定義在配置文件中,并且在變量中不定義默認值:
variable "access_key_id" {
description = "The Access Key ID for operating your infrastructure"
}
variable "access_key_secret" {
description = "The Access Key Secret for operating your infrastructure"
}
variable "security_token" {
description = "The Security Token for operating your infrastructure"
}
provider "alicloud" {
access_key = var.access_key_id
secret_key = var.access_key_secret
# 如果是 STS 的訪問憑證,此處需要配置 security_token
# security_token = var.security_token
}
當運行 terraform 命令時可以通過 -var 選項傳入具體變量值:
$ terraform plan -var access_key_id="Abc12345" -var access_key_secret="Abc12345" -var security_token="Abc12345"
環境變量配置
基于環境變量身份認證方式跟靜態配置的區別是將訪問憑證保存在特定的環境變量中,當執行 Terraform 命令時,如果配置模板中沒有顯示聲明訪問憑證,那么將嘗試從如下的環境變量中獲取。環境變量的設置方式如下:
Linux
使用export命令配置的臨時環境變量僅對當前會話有效,當會話退出之后所設置的環境變量將會丟失。如需長期保留環境變量,可將export命令配置到操作系統的啟動配置文件中。
# Access Key Id
$ export ALICLOUD_ACCESS_KEY="<你的 Access Key ID>"
# Access Key Secret
$ export ALICLOUD_SECRET_KEY="<你的 Access Key Secret>"
# 如果是 STS 的訪問憑證,此處需要配置 security_token
$ export ALICLOUD_SECURITY_TOKEN="<你的訪問 Token>"
Windows
在桌面右鍵單擊此電腦,選擇
。在系統變量/用戶變量中,單擊新建,創建以下環境變量。
變量名
變量描述
變量值
ALICLOUD_ACCESS_KEY
Access Key Id
示例:LTAIUrZCw3********
ALICLOUD_SECRET_KEY
Access Key Secret
示例:zfwwWAMWIAiooj14GQ2*************
ALICLOUD_SECURITY_TOKEN(可選)
如果是 STS 的訪問憑證,此處需要配置Security Token
示例:sts.fr2nlrnlwnelr3*******
設置了環境變量之后,provider 塊可以不在配置模板中顯示聲明或者只聲明地域信息:
provider "alicloud" {
region = "cn-hangzhou"
}
當然,region 也是支持通過環境變量 ALICLOUD_REGION
進行配置的。如果 region 沒有顯式聲明也沒有配置環境變量,cn-beijing 將是其默認配置值。
相比于靜態配置,環境變量的配置方式更簡單,安全性也好一些。
ECS 服務角色
當在 ECS 實例上運行 Terraform 來管理阿里云資源時,除了如上的靜態配置和環境變量配置外,還有一種免配置訪問憑證的方式:ECS 服務角色,即阿里云 RAM 角色允許您將一個角色關聯到 ECS 實例上,實現在實例內部自動獲取并刷新臨時訪問憑證的能力,無需直接暴露 AccessKey,減少密鑰泄露的風險;同時,也可借助 RAM 角色的精細化訪問權限控制來避免權限過度分配。詳見實例RAM角色。
基于 ECS 服務角色的身份認證配置方式非常簡單:
準備一臺 ECS 實例,該實例要具備公網訪問能力;
創建一個 RAM 角色,并將該角色綁定到 ECS 實例上;
在 provider 塊中定義 ecs_role_name 參數,并將 RAM 角色名賦值給此參數:
provider "alicloud" {
ecs_role_name = "<綁定到 ECS 實例上的 RAM 角色名稱>"
}
當然,也可以通過環境變量 ALICLOUD_ECS_ROLE_NAME
來賦值。
基于 ECS 服務角色的認證方式,安全性高,當在 ECS 實例中執行 Terraform 時,我們強烈推薦使用該認證方式。
角色扮演(AssumeRole)
通常訪問和管理阿里云資源的主體是 RAM 用戶或者云服務(比如 ECS 服務),對應的訪問憑證也是 RAM 用戶的 AccessKey 或者通過云服務角色換取到的 STS AccessKey,相應的訪問權限也是由綁定到 RAM 用戶或者云服務角色上的權限策略所決定的。當我們想要將訪問權限跟 RAM 用戶或者云服務角色分離,或者想跨賬號訪問云資源時,可以使用角色扮演的身份認證方式,將 RAM 用戶或者云服務角色授權(Assume)給某個具體的 RAM 角色,讓這個 RAM 角色獲取一個臨時身份訪問憑證,進而完成資源的訪問。
基于角色扮演的身份認證是通過調用 AssumeRole - 獲取扮演角色的臨時身份憑證 來實現的,因此在 Terraform 中配置角色扮演身份認證前,首先需要準備如下內容:
創建一個 RAM 用戶,并為該用戶授權系統策略 AliyunSTSAssumeRoleAccess,使其能夠訪問 AssumeRole API
為 RAM 用戶創建 AccessKey,用于在 Terraform 中調用 AssumeRole API 換取臨時身份訪問憑證
創建一個授信實體為“阿里云賬號”的 RAM 角色,并為該角色授權想要訪問的云服務的權限策略(比如訪問 OSS 的全部訪問權限 AliyunOSSFullAccess),并記錄該 RAM 角色對應的 ARN
根據自身場景,編寫需要訪問的云資源的 RAM 自定義權限策略(比如只訪問杭州地域的所有 Bucket),用于和授權給 RAM 角色的權限策略取交集,實現精細化的訪問控制
在準備好如上內容后,在 provider 塊中按照如下的方式進行聲明:
provider "alicloud" {
# 用于調用 AssumeRole 的 RAM 用戶的 AccessKey ID
access_key = "<RAM 用戶的 AccessKey ID>"
# 用于調用 AssumeRole 的 RAM 用戶的 AccessKey Secret
secret_key = "<RAM 用戶的 AccessKey Secret>"
assume_role {
role_arn = "<一個 RAM 角色的 ARN>"
policy = "<一個 RAM 權限策略的具體內容>"
session_name = "<一個自定義的角色會話名稱>"
session_expiration = <臨時身份訪問憑證的最大有效期>
}
}
在 Terraform 中配置角色扮演的身份認證時,支持如下參數:
access_key / secret_key
當扮演 RAM 用戶的臨時身份時,access_key 和 secret_key 時必填的,并且必須被授予 AssumeRole 的訪問權限,否則無法通過 AssumeRole 獲取到臨時訪問憑證。和靜態設置一樣,該參數也可以通過環境變量的方式來設置。
assume_role
assume_role 是一個參數塊,用來設置獲取臨時身份的參數,其包含如下參數:
role_arn,必填參數,標識使用哪個角色來扮演身份,其值的格式為:
acs:ram::<阿里云賬號ID>:role/<RAM 角色名稱>
,如:acs:ram::151192xxxxxx:role/k8srolepolicy,選填參數,指定角色扮演的臨時身份被授權了哪些權限。該參數為非必填參數,如果指定該權限策略,則臨時身份最終的權限策略取決于扮演的 RAM 角色綁定的權限策略與該權限策略的交集;如果不指定該權限策略,則臨時身份最終的權限策略取決于扮演的 RAM 角色綁定的權限策略。
session_name,選填參數,標識角色會話名稱。該參數為用戶自定義參數。通常設置為調用角色扮演的用戶身份,例如:用戶名。如果不設置,阿里云 Provider 將默認值設置為 terraform。
session_expiration,選填參數,標識臨時身份的有效期,單位是秒,即多少秒之后換取到的臨時身份將失效。該參數最小值為 900 秒,最大值為扮演的 RAM 角色的
MaxSessionDuration
時間,MaxSessionDuration
默認值為 3600 秒,可以通過 UpdateRole - 更新角色信息 來修改最大會話時間,能修改的最大值為 43200 秒。external_Id,選填參數,標識角色外部 ID。該參數為外部提供的用于表示角色的參數信息,主要功能是防止混淆代理人問題。更多信息,請參見使用ExternalId防止混淆代理人問題。
如下是一個角色扮演的示例,并允許獲取杭州的 OSS Bucket 的列表:
provider "alicloud" {
# 為了安全起見,此處的 access_key 和 secret_key 已經通過環境變量進行了設置
region = "cn-hangzhou"
assume_role {
role_arn = "acs:ram::11827xxxxxx:role/tf-assume-role"
policy = <<EOF
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:ListBuckets",
"Resource": "acs:oss:oss-cn-hangzhou:*:*"
}
]
}
EOF
session_name = "terraform-assume-role-session"
session_expiration = 1000
}
}
需要注意的是,運行本示例之前已經為 RAM 角色 tf-assume-role 設置了 AliyunOSSFullAccess 的權限,否則當訪問杭州 OSS Bucket 的時候將報無權限的錯誤。
當然,如果不想通過 policy 參數來設置精細化的訪問策略,也可以直接將上述 policy 的權限直接授權給 RAM 角色 tf-assume-role,這樣只需要在 assume_role 塊中指定 role_arn 即可。
如果 Terraform 的運行環境是 ECS 實例,那么可以結合 ECS 服務角色來消除對 AccessKey 的暴露,此時上述的示例可以改為如下的設置方式:
provider "alicloud" {
ecs_role_name = "<綁定到 ECS 實例上的 RAM 角色名稱>"
region = "cn-hangzhou"
assume_role {
role_arn = "acs:ram::11827xxxxxx:role/tf-assume-role"
policy = <<EOF
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:ListBuckets",
"Resource": "acs:oss:oss-cn-hangzhou:*:*"
}
]
}
EOF
session_name = "terraform-assume-role-session"
session_expiration = 1000
}
}
此時,只需要為綁定到 ECS 實例上的 RAM 角色授權系統策略 AliyunSTSAssumeRoleAccess,使其能夠訪問 AssumeRole API 即可。
OIDC 角色扮演(AssumeRoleWithOIDC)
和角色扮演(AssumeRole)類似,OIDC 角色扮演也是通過獲取扮演 RAM角色 的臨時身份憑證來實現對阿里云資源的訪問的,唯一的不同是,OIDC 角色扮演要扮演的身份由 OIDC 身份提供商頒發的,詳見管理OIDC身份提供商。
基于 OIDC 角色扮演的身份認證是通過調用 AssumeRoleWithOIDC - OIDC角色SSO時獲取扮演角色的臨時身份憑證 來實現的,因此在 Terraform 中配置 OIDC 角色扮演身份認證前,首先需要準備如下內容:
創建一個 OIDC 身份提供商,并從外部 IdP 申請簽發 OIDC 令牌(OIDC Token),記錄 OIDC 身份提供商的 ARN 和 OIDC Token
創建一個授信實體為“身份提供商”的 RAM 角色,并為該角色授權想要訪問的云服務的權限策略(比如訪問 OSS 的全部訪問權限 AliyunOSSFullAccess),并記錄該 RAM 角色對應的 ARN
根據自身場景,編寫需要訪問的云資源的 RAM 自定義權限策略(比如只訪問杭州地域的所有 Bucket),用于和授權給 RAM 角色的權限策略取交集,實現精細化的訪問控制
在準備好如上內容后,在 provider 塊中按照如下的方式進行聲明:
provider "alicloud" {
assume_role_with_oidc {
oidc_provider_arn = "<一個 OIDC 身份提供商的 ARN>"
oidc_token = "<外部 IDP 申請簽發的 OIDC Token>"
role_arn = "<一個 RAM 角色的 ARN>"
policy = "<一個 RAM 權限策略的具體內容>"
role_session_name = "<一個自定義的角色會話名稱>"
session_expiration = <臨時身份訪問憑證的最大有效期>
}
}
在 Terraform 中配置 OIDC 角色扮演的身份認證時,所有的參數都放在 assume_role_with_oidc 參數塊中,其支持如下參數:
oidc_provider_arn,必填參數,標識OIDC 身份提供商的 ARN,其值的格式為:
acs:ram::<阿里云賬號ID>:oidc-provider/<RAM Provider 角色名稱>
,如:acs:ram::151192xxxxxx:oidc-provider/ackrole,您可以通過 RAM 控制臺或 API 查看 OIDC 身份提供商的 ARN。該參數支持通過環境變量 ALIBABA_CLOUD_OIDC_PROVIDER_ARN 設置。oidc_token,選填參數,標識由外部 IdP 簽發的 OIDC 令牌(OIDC Token),長度:4~20000 個字符。該參數和 參數 oidc_token_file 兩者必須設置一個。
oidc_token_file,選填參數,標識存放由外部 IdP 簽發的 OIDC 令牌(OIDC Token)的文件絕對路徑。該參數和 參數 oidc_token_file 兩者必須設置一個,并且支持通過環境變量 ALIBABA_CLOUD_OIDC_TOKEN_FILE 設置。
role_arn,必填參數,標識使用哪個角色來扮演身份,其值的格式為:
acs:ram::<阿里云賬號ID>:role/<RAM 角色名稱>
,如:acs:ram::151192xxxxxx:role/k8srole,支持通過環境變量 ALIBABA_CLOUD_ROLE_ARN 設置。policy,選填參數,指定角色扮演的臨時身份被授權了哪些權限。該參數為非必填參數,如果指定該權限策略,則臨時身份最終的權限策略取決于扮演的 RAM 角色綁定的權限策略與該權限策略的交集;如果不指定該權限策略,則臨時身份最終的權限策略取決于扮演的 RAM 角色綁定的權限策略。
role_session_name,選填參數,標識角色會話名稱。該參數為用戶自定義參數。通常設置為調用角色扮演的用戶身份,例如:用戶名。如果不設置,阿里云 Provider 將默認值設置為 terraform。該參數支持通過環境變量 ALIBABA_CLOUD_ROLE_SESSION_NAME 設置。
session_expiration,選填參數,標識臨時身份的有效期,單位是秒,即多少秒之后換取到的臨時身份將失效。該參數最小值為 900 秒,最大值為扮演的 RAM 角色的
MaxSessionDuration
時間,MaxSessionDuration
默認值為 3600 秒,可以通過 UpdateRole - 更新角色信息 來修改最大會話時間,能修改的最大值為 43200 秒。
目前阿里云 ACK 已經支持通過開啟 RRSA 功能來實現 OIDC Provider 的創建和 OIDC 令牌的簽發,詳見:通過RRSA配置ServiceAccount的RAM權限實現Pod權限隔離,并且在開啟 RRSA 功能后,ack-pod-identity-webhook組件已為 Pod 自動注入了配置 ALIBABA_CLOUD_OIDC_PROVIDER_ARN,ALIBABA_CLOUD_OIDC_TOKEN_FILE,ALIBABA_CLOUD_ROLE_ARN,此時如果在 ACK 內運行 Terraform 命令,上述的獲取杭州的 OSS Bucket 的列表的示例可以簡化為:
provider "alicloud" {
region = "cn-hangzhou"
assume_role_with_oidc {
policy = <<EOF
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:ListBuckets",
"Resource": "acs:oss:oss-cn-hangzhou:*:*"
}
]
}
EOF
session_name = "terraform-assume-role-session"
session_expiration = 1000
}
}
和角色扮演一樣,如果不想通過 policy 參數來設置精細化的訪問策略,也可以直接將上述 policy 的權限直接授權給 RAM 角色,這樣上述的示例可以進一步得到簡化:
provider "alicloud" {
region = "cn-hangzhou"
assume_role_with_oidc {
policy = <<EOF
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:ListBuckets",
"Resource": "acs:oss:oss-cn-hangzhou:*:*"
}
]
}
EOF
session_name = "terraform-assume-role-session"
session_expiration = 1000
}
}
共享的配置文件(profile)
共享額配置文件 - Profile 是阿里云 CLI 提供的一個通用功能,用于用統一的方式配置訪問阿里云資源所需的憑證信息。目前 Profile 對訪問憑證的設置支持對靜態配置、ECS 服務角色、角色扮演這三種方式,具體的配置方式詳見配置憑證。
當使用阿里云 CLI 完成多個憑證的配置后,Terraform 可以直接基于 Profile 的名稱來配置身份認證方式:
provider "alicloud" {
region = "cn-hangzhou"
shared_credentials_file = "<Profile 配置文件的絕對路徑>"
profile = "<所要使用的 Profile 的名稱>"
}
在 Terraform 中通過 Profile 配置身份認證時,支持如下參數:
profile,必填參數,profile 的名稱,標識將使用哪個 profile 來進行身份認證
shared_credentials_file,選填參數,標識profile 的存儲位置,該文件可以在通過 CLI 設置 profile 的時候通過選項 --config-path 來指定。
配置了 Profile 的后,當涉及到多環境切換或者多個賬號切換的時候將非常方便。比如,想要在開發測試環境中分別在北京和杭州創建阿里云資源,此時 provider 的配置方式可以使用如下的方式:
provider "alicloud" {
alias = beijing
region = "cn-beijing"
profile = "bj-test"
}
provider "alicloud" {
alias = hangzhou
region = "cn-hangzhou"
profile = "hz-test"
}
總結
最后,對上述身份認證方式做個總結。
優先級
通常在配置 provider 的時候,只選擇其中的一種身份認證方式,但是當同時設置了多種認證方式后,將按照優先級順序選擇優先級最高的認證方式,具體的優先級如下:靜態配置 > 環境變量 > Profile 靜態配置 > ECS 服務角色 > Profile ECS 服務角色 > OIDC 角色扮演 > 角色扮演
安全性
不同的身份認證方式都有不同的適用場景,當 Terraform 應用到生產環境的時候,安全性是必須要考慮的因素。我們推薦 ECS 服務角色、角色扮演、OIDC 角色扮演三種認證方式,這三種方式使用的是臨時身份,一方面無需直接暴露 AccessKey,減少密鑰泄露的風險,另一方面,臨時身份可以設置過期時間,可以有效地控制暴露范圍。
精細化授權
在企業生產環境中,通常都會按照應用、團隊、項目等維度對資源管理的權限進行嚴格的控制,此時對權限策略的精細化控制就變得至關重要。角色扮演、OIDC 角色扮演是我們推薦的精細化授權的認證方式,可以按照不同項目或者應用的基礎設施代碼設置不同的權限策略。