diff --git a/.changelog/2739.txt b/.changelog/2739.txt new file mode 100644 index 0000000000..44bd776f49 --- /dev/null +++ b/.changelog/2739.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +provider: support securityToken for credentials +``` diff --git a/.changelog/2741.txt b/.changelog/2741.txt new file mode 100644 index 0000000000..f27d3762f7 --- /dev/null +++ b/.changelog/2741.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +provider: add SAML, OIDC for STS client +``` diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index e66ac94835..1e4e3868f6 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -123,11 +123,14 @@ const ( PROVIDER_DOMAIN = "TENCENTCLOUD_DOMAIN" //internal version: replace envYunti begin, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. //internal version: replace envYunti end, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. - PROVIDER_ASSUME_ROLE_ARN = "TENCENTCLOUD_ASSUME_ROLE_ARN" - PROVIDER_ASSUME_ROLE_SESSION_NAME = "TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME" - PROVIDER_ASSUME_ROLE_SESSION_DURATION = "TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION" - PROVIDER_SHARED_CREDENTIALS_DIR = "TENCENTCLOUD_SHARED_CREDENTIALS_DIR" - PROVIDER_PROFILE = "TENCENTCLOUD_PROFILE" + PROVIDER_ASSUME_ROLE_ARN = "TENCENTCLOUD_ASSUME_ROLE_ARN" + PROVIDER_ASSUME_ROLE_SESSION_NAME = "TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME" + PROVIDER_ASSUME_ROLE_SESSION_DURATION = "TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION" + PROVIDER_ASSUME_ROLE_SAML_ASSERTION = "TENCENTCLOUD_ASSUME_ROLE_SAML_ASSERTION" + PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN = "TENCENTCLOUD_ASSUME_ROLE_PRINCIPAL_ARN" + PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN = "TENCENTCLOUD_ASSUME_ROLE_WEB_IDENTITY_TOKEN" + PROVIDER_SHARED_CREDENTIALS_DIR = "TENCENTCLOUD_SHARED_CREDENTIALS_DIR" + PROVIDER_PROFILE = "TENCENTCLOUD_PROFILE" ) const ( @@ -195,7 +198,7 @@ func Provider() *schema.Provider { //internal version: replace enableBpass begin, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. //internal version: replace enableBpass end, please do not modify this annotation and refrain from inserting any code between the beginning and end lines of the annotation. "assume_role": { - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, MaxItems: 1, Description: "The `assume_role` block. If provided, terraform will attempt to assume this role using the supplied credentials.", @@ -230,6 +233,29 @@ func Provider() *schema.Provider { Optional: true, Description: "A more restrictive policy when making the AssumeRole call. Its content must not contains `principal` elements. Notice: more syntax references, please refer to: [policies syntax logic](https://intl.cloud.tencent.com/document/product/598/10603).", }, + "saml_assertion": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_SAML_ASSERTION, nil), + ConflictsWith: []string{"assume_role.0.web_identity_token"}, + RequiredWith: []string{"assume_role.0.principal_arn"}, + Description: "SAML assertion information encoded in base64. And it can't be used with `web_identity_token` together.", + }, + "principal_arn": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN, nil), + ConflictsWith: []string{"assume_role.0.web_identity_token"}, + RequiredWith: []string{"assume_role.0.saml_assertion"}, + Description: "Player Access Description Name. And it can't be used with `web_identity_token` together.", + }, + "web_identity_token": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN, nil), + ConflictsWith: []string{"assume_role.0.saml_assertion", "assume_role.0.principal_arn"}, + Description: "OIDC token issued by IdP. And it can't be used with `saml_assertion` or `principal_arn` together.", + }, }, }, }, @@ -1993,17 +2019,6 @@ func Provider() *schema.Provider { } func providerConfigure(d *schema.ResourceData) (interface{}, error) { - //var getProviderConfig = func(str string, key string) string { - // if str == "" { - // value, err := getConfigFromProfile(d, key) - // if err == nil && value != nil { - // str = value.(string) - // } - // } - // - // return str - //} - var getProviderConfig = func(key string) string { var str string value, err := getConfigFromProfile(d, key) @@ -2037,6 +2052,8 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { if v, ok := d.GetOk("security_token"); ok { securityToken = v.(string) + } else { + securityToken = getProviderConfig("token") } if v, ok := d.GetOk("region"); ok { @@ -2070,10 +2087,13 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { } var ( - assumeRoleArn string - assumeRoleSessionName string - assumeRoleSessionDuration int - assumeRolePolicy string + assumeRoleArn string + assumeRoleSessionName string + assumeRoleSessionDuration int + assumeRolePolicy string + assumeRoleSamlAssertion string + assumeRolePrincipalArn string + assumeRoleWebIdentityToken string ) // get assume role from credential @@ -2108,25 +2128,57 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { assumeRoleSessionDuration = 7200 } - _ = genClientWithSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, "") + envSamlAssertion := os.Getenv(PROVIDER_ASSUME_ROLE_SAML_ASSERTION) + envPrincipalArn := os.Getenv(PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN) + envWebIdentityToken := os.Getenv(PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN) + + if envSamlAssertion == "" && envPrincipalArn == "" && envWebIdentityToken == "" { + // use assume role + _ = genClientWithSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, "") + } else if envSamlAssertion != "" && envPrincipalArn != "" { + // use assume role with saml + _ = genClientWithSamlSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, envSamlAssertion, envPrincipalArn) + } else if envWebIdentityToken != "" { + // use assume role with oidc + _ = genClientWithOidcSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, envWebIdentityToken) + } else { + return nil, fmt.Errorf("get `assume_role` from env error.\n") + } } // get assume role from tf if v, ok := d.GetOk("assume_role"); ok { - assumeRoleList := v.(*schema.Set).List() + assumeRoleList := v.([]interface{}) if len(assumeRoleList) == 1 { + // assume role assumeRole := assumeRoleList[0].(map[string]interface{}) assumeRoleArn = assumeRole["role_arn"].(string) assumeRoleSessionName = assumeRole["session_name"].(string) assumeRoleSessionDuration = assumeRole["session_duration"].(int) assumeRolePolicy = assumeRole["policy"].(string) + // saml + assumeRoleSamlAssertion = assumeRole["saml_assertion"].(string) + assumeRolePrincipalArn = assumeRole["principal_arn"].(string) + // oidc + assumeRoleWebIdentityToken = assumeRole["web_identity_token"].(string) - _ = genClientWithSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRolePolicy) + if assumeRoleSamlAssertion == "" && assumeRolePrincipalArn == "" && assumeRoleWebIdentityToken == "" { + // use assume role + _ = genClientWithSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRolePolicy) + } else if assumeRoleSamlAssertion != "" && assumeRolePrincipalArn != "" { + // use assume role with saml + _ = genClientWithSamlSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRoleSamlAssertion, assumeRolePrincipalArn) + } else if assumeRoleWebIdentityToken != "" { + // use assume role with oidc + _ = genClientWithOidcSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRoleWebIdentityToken) + } else { + return nil, fmt.Errorf("get `assume_role` params error.\n") + } } } if secretId == "" || secretKey == "" { - return nil, fmt.Errorf("Please set your `secret_id` and `secret_key`.") + return nil, fmt.Errorf("Please set your `secret_id` and `secret_key`.\n") } return &tcClient, nil @@ -2158,6 +2210,56 @@ func genClientWithSTS(tcClient *TencentCloudClient, assumeRoleArn, assumeRoleSes return nil } +func genClientWithSamlSTS(tcClient *TencentCloudClient, assumeRoleArn, assumeRoleSessionName string, assumeRoleSessionDuration int, assumeRoleSamlAssertion, assumeRolePrincipalArn string) error { + // applying STS credentials + request := sdksts.NewAssumeRoleWithSAMLRequest() + request.RoleArn = helper.String(assumeRoleArn) + request.RoleSessionName = helper.String(assumeRoleSessionName) + request.DurationSeconds = helper.IntUint64(assumeRoleSessionDuration) + request.SAMLAssertion = helper.String(assumeRoleSamlAssertion) + request.PrincipalArn = helper.String(assumeRolePrincipalArn) + + ratelimit.Check(request.GetAction()) + response, err := tcClient.apiV3Conn.UseStsClient().AssumeRoleWithSAML(request) + if err != nil { + return err + } + + // using STS credentials + tcClient.apiV3Conn.Credential = sdkcommon.NewTokenCredential( + *response.Response.Credentials.TmpSecretId, + *response.Response.Credentials.TmpSecretKey, + *response.Response.Credentials.Token, + ) + + return nil +} + +func genClientWithOidcSTS(tcClient *TencentCloudClient, assumeRoleArn, assumeRoleSessionName string, assumeRoleSessionDuration int, assumeRolePolicy string) error { + // applying STS credentials + request := sdksts.NewAssumeRoleWithWebIdentityRequest() + request.ProviderId = helper.String("OIDC") + request.RoleArn = helper.String(assumeRoleArn) + request.RoleSessionName = helper.String(assumeRoleSessionName) + request.DurationSeconds = helper.IntInt64(assumeRoleSessionDuration) + request.WebIdentityToken = helper.String(assumeRolePolicy) + + ratelimit.Check(request.GetAction()) + response, err := tcClient.apiV3Conn.UseStsClient().AssumeRoleWithWebIdentity(request) + if err != nil { + return err + } + + // using STS credentials + tcClient.apiV3Conn.Credential = sdkcommon.NewTokenCredential( + *response.Response.Credentials.TmpSecretId, + *response.Response.Credentials.TmpSecretKey, + *response.Response.Credentials.Token, + ) + + return nil +} + var providerConfig map[string]interface{} func getConfigFromProfile(d *schema.ResourceData, ProfileKey string) (interface{}, error) {