Skip to content

Commit 5dd40e4

Browse files
authored
feat(provider): [118694466] add SAML, OIDC for STS client (#2742)
* add * add * add * add * add * add
1 parent 7018307 commit 5dd40e4

File tree

5 files changed

+317
-18
lines changed

5 files changed

+317
-18
lines changed

.changelog/2742.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
provider: add SAML, OIDC for STS client
3+
```

tencentcloud/connectivity/client.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,17 +566,22 @@ func (me *TencentCloudClient) UseCamClient() *cam.Client {
566566
}
567567

568568
// UseStsClient returns sts client for service
569-
func (me *TencentCloudClient) UseStsClient() *sts.Client {
569+
func (me *TencentCloudClient) UseStsClient(stsExtInfo ...StsExtInfo) *sts.Client {
570570
/*
571571
me.Credential will changed, don't cache it
572572
if me.stsConn != nil {
573573
return me.stsConn
574574
}
575575
*/
576576

577+
var logRoundTripper LogRoundTripper
578+
if len(stsExtInfo) != 0 {
579+
logRoundTripper.Authorization = stsExtInfo[0].Authorization
580+
}
581+
577582
cpf := me.NewClientProfile(300)
578583
me.stsConn, _ = sts.NewClient(me.Credential, me.Region, cpf)
579-
me.stsConn.WithHttpTransport(&LogRoundTripper{})
584+
me.stsConn.WithHttpTransport(&logRoundTripper)
580585

581586
return me.stsConn
582587
}

tencentcloud/connectivity/transport.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@ func SetReqClient(name string) {
2525
}
2626

2727
type LogRoundTripper struct {
28-
InstanceId string
28+
InstanceId string
29+
Authorization string
2930
}
3031

3132
type IacExtInfo struct {
3233
InstanceId string
3334
}
3435

36+
type StsExtInfo struct {
37+
Authorization string
38+
}
39+
3540
func (me *LogRoundTripper) RoundTrip(request *http.Request) (response *http.Response, errRet error) {
3641

3742
var inBytes, outBytes []byte
@@ -60,6 +65,10 @@ func (me *LogRoundTripper) RoundTrip(request *http.Request) (response *http.Resp
6065
reqClientFormat = fmt.Sprintf("%s,id=%s", ReqClient, me.InstanceId)
6166
}
6267

68+
if me.Authorization != "" {
69+
request.Header.Set("Authorization", me.Authorization)
70+
}
71+
6372
request.Header.Set("X-TC-RequestClient", reqClientFormat)
6473
inBytes = []byte(fmt.Sprintf("%s, request: ", request.Header[headName]))
6574
requestBody, errRet := ioutil.ReadAll(bodyReader)

tencentcloud/provider.go

Lines changed: 212 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,14 @@ const (
124124
PROVIDER_DOMAIN = "TENCENTCLOUD_DOMAIN"
125125
//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.
126126
//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.
127-
PROVIDER_ASSUME_ROLE_ARN = "TENCENTCLOUD_ASSUME_ROLE_ARN"
128-
PROVIDER_ASSUME_ROLE_SESSION_NAME = "TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME"
129-
PROVIDER_ASSUME_ROLE_SESSION_DURATION = "TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION"
130-
PROVIDER_SHARED_CREDENTIALS_DIR = "TENCENTCLOUD_SHARED_CREDENTIALS_DIR"
131-
PROVIDER_PROFILE = "TENCENTCLOUD_PROFILE"
127+
PROVIDER_ASSUME_ROLE_ARN = "TENCENTCLOUD_ASSUME_ROLE_ARN"
128+
PROVIDER_ASSUME_ROLE_SESSION_NAME = "TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME"
129+
PROVIDER_ASSUME_ROLE_SESSION_DURATION = "TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION"
130+
PROVIDER_ASSUME_ROLE_SAML_ASSERTION = "TENCENTCLOUD_ASSUME_ROLE_SAML_ASSERTION"
131+
PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN = "TENCENTCLOUD_ASSUME_ROLE_PRINCIPAL_ARN"
132+
PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN = "TENCENTCLOUD_ASSUME_ROLE_WEB_IDENTITY_TOKEN"
133+
PROVIDER_SHARED_CREDENTIALS_DIR = "TENCENTCLOUD_SHARED_CREDENTIALS_DIR"
134+
PROVIDER_PROFILE = "TENCENTCLOUD_PROFILE"
132135
)
133136

134137
const (
@@ -234,6 +237,94 @@ func Provider() *schema.Provider {
234237
},
235238
},
236239
},
240+
"assume_role_with_saml": {
241+
Type: schema.TypeList,
242+
Optional: true,
243+
MaxItems: 1,
244+
ConflictsWith: []string{"assume_role_with_web_identity"},
245+
Description: "The `assume_role_with_saml` block. If provided, terraform will attempt to assume this role using the supplied credentials.",
246+
Elem: &schema.Resource{
247+
Schema: map[string]*schema.Schema{
248+
"saml_assertion": {
249+
Type: schema.TypeString,
250+
Required: true,
251+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_SAML_ASSERTION, nil),
252+
Description: "SAML assertion information encoded in base64. It can be sourced from the `PROVIDER_ASSUME_ROLE_SAML_ASSERTION`.",
253+
},
254+
"principal_arn": {
255+
Type: schema.TypeString,
256+
Required: true,
257+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN, nil),
258+
Description: "Player Access Description Name. It can be sourced from the `PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN`.",
259+
},
260+
"role_arn": {
261+
Type: schema.TypeString,
262+
Required: true,
263+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_ARN, nil),
264+
Description: "The ARN of the role to assume. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_ARN`.",
265+
},
266+
"session_name": {
267+
Type: schema.TypeString,
268+
Required: true,
269+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_SESSION_NAME, nil),
270+
Description: "The session name to use when making the AssumeRole call. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME`.",
271+
},
272+
"session_duration": {
273+
Type: schema.TypeInt,
274+
Required: true,
275+
DefaultFunc: func() (interface{}, error) {
276+
if v := os.Getenv(PROVIDER_ASSUME_ROLE_SESSION_DURATION); v != "" {
277+
return strconv.Atoi(v)
278+
}
279+
return 7200, nil
280+
},
281+
ValidateFunc: tccommon.ValidateIntegerInRange(0, 43200),
282+
Description: "The duration of the session when making the AssumeRoleWithSAML call. Its value ranges from 0 to 43200(seconds), and default is 7200 seconds. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION`.",
283+
},
284+
},
285+
},
286+
},
287+
"assume_role_with_web_identity": {
288+
Type: schema.TypeList,
289+
Optional: true,
290+
MaxItems: 1,
291+
ConflictsWith: []string{"assume_role_with_saml"},
292+
Description: "The `assume_role_with_web_identity` block. If provided, terraform will attempt to assume this role using the supplied credentials.",
293+
Elem: &schema.Resource{
294+
Schema: map[string]*schema.Schema{
295+
"web_identity_token": {
296+
Type: schema.TypeString,
297+
Required: true,
298+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN, nil),
299+
Description: "OIDC token issued by IdP. It can be sourced from the `PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN`.",
300+
},
301+
"role_arn": {
302+
Type: schema.TypeString,
303+
Required: true,
304+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_ARN, nil),
305+
Description: "The ARN of the role to assume. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_ARN`.",
306+
},
307+
"session_name": {
308+
Type: schema.TypeString,
309+
Required: true,
310+
DefaultFunc: schema.EnvDefaultFunc(PROVIDER_ASSUME_ROLE_SESSION_NAME, nil),
311+
Description: "The session name to use when making the AssumeRole call. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_NAME`.",
312+
},
313+
"session_duration": {
314+
Type: schema.TypeInt,
315+
Required: true,
316+
DefaultFunc: func() (interface{}, error) {
317+
if v := os.Getenv(PROVIDER_ASSUME_ROLE_SESSION_DURATION); v != "" {
318+
return strconv.Atoi(v)
319+
}
320+
return 7200, nil
321+
},
322+
ValidateFunc: tccommon.ValidateIntegerInRange(0, 43200),
323+
Description: "The duration of the session when making the AssumeRoleWithWebIdentity call. Its value ranges from 0 to 43200(seconds), and default is 7200 seconds. It can be sourced from the `TENCENTCLOUD_ASSUME_ROLE_SESSION_DURATION`.",
324+
},
325+
},
326+
},
327+
},
237328
"shared_credentials_dir": {
238329
Type: schema.TypeString,
239330
Optional: true,
@@ -2020,6 +2111,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
20202111
domain string
20212112
)
20222113

2114+
needSecret := true
20232115
if v, ok := d.GetOk("secret_id"); ok {
20242116
secretId = v.(string)
20252117
} else {
@@ -2087,7 +2179,6 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
20872179
if assumeRoleArn != "" && assumeRoleSessionName != "" {
20882180
assumeRoleSessionDuration = 7200
20892181
assumeRolePolicy = ""
2090-
20912182
_ = genClientWithSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRolePolicy)
20922183
}
20932184

@@ -2107,7 +2198,28 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
21072198
assumeRoleSessionDuration = 7200
21082199
}
21092200

2110-
_ = genClientWithSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, "")
2201+
// get assume role with saml from env
2202+
envSamlAssertion := os.Getenv(PROVIDER_ASSUME_ROLE_SAML_ASSERTION)
2203+
envPrincipalArn := os.Getenv(PROVIDER_ASSUME_ROLE_PRINCIPAL_ARN)
2204+
// get assume role with web identity from env
2205+
envWebIdentityToken := os.Getenv(PROVIDER_ASSUME_ROLE_WEB_IDENTITY_TOKEN)
2206+
2207+
if envSamlAssertion == "" && envPrincipalArn == "" && envWebIdentityToken == "" {
2208+
// use assume role
2209+
_ = genClientWithSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, "")
2210+
} else if envSamlAssertion != "" && envPrincipalArn != "" && envWebIdentityToken != "" {
2211+
return nil, fmt.Errorf("can not set `TENCENTCLOUD_ASSUME_ROLE_SAML_ASSERTION`, `TENCENTCLOUD_ASSUME_ROLE_PRINCIPAL_ARN`, `TENCENTCLOUD_ASSUME_ROLE_WEB_IDENTITY_TOKEN` at the same time.\n")
2212+
} else if envSamlAssertion != "" && envPrincipalArn != "" {
2213+
// use assume role with saml
2214+
_ = genClientWithSamlSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, envSamlAssertion, envPrincipalArn)
2215+
needSecret = false
2216+
} else if envWebIdentityToken != "" {
2217+
// use assume role with oidc
2218+
_ = genClientWithOidcSTS(&tcClient, envRoleArn, envSessionName, assumeRoleSessionDuration, envWebIdentityToken)
2219+
needSecret = false
2220+
} else {
2221+
return nil, fmt.Errorf("get `assume_role` from env error.\n")
2222+
}
21112223
}
21122224

21132225
// get assume role from tf
@@ -2124,8 +2236,45 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
21242236
}
21252237
}
21262238

2127-
if secretId == "" || secretKey == "" {
2128-
return nil, fmt.Errorf("Please set your `secret_id` and `secret_key`.")
2239+
var (
2240+
assumeRoleSamlAssertion string
2241+
assumeRolePrincipalArn string
2242+
assumeRoleWebIdentityToken string
2243+
)
2244+
2245+
// get assume role with saml from tf
2246+
if v, ok := d.GetOk("assume_role_with_saml"); ok {
2247+
assumeRoleWithSamlList := v.([]interface{})
2248+
if len(assumeRoleWithSamlList) == 1 {
2249+
assumeRoleWithSaml := assumeRoleWithSamlList[0].(map[string]interface{})
2250+
assumeRoleSamlAssertion = assumeRoleWithSaml["saml_assertion"].(string)
2251+
assumeRolePrincipalArn = assumeRoleWithSaml["principal_arn"].(string)
2252+
assumeRoleArn = assumeRoleWithSaml["role_arn"].(string)
2253+
assumeRoleSessionName = assumeRoleWithSaml["session_name"].(string)
2254+
assumeRoleSessionDuration = assumeRoleWithSaml["session_duration"].(int)
2255+
2256+
_ = genClientWithSamlSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRoleSamlAssertion, assumeRolePrincipalArn)
2257+
needSecret = false
2258+
}
2259+
}
2260+
2261+
// get assume role with web identity from tf
2262+
if v, ok := d.GetOk("assume_role_with_web_identity"); ok {
2263+
assumeRoleWithWebIdentityList := v.([]interface{})
2264+
if len(assumeRoleWithWebIdentityList) == 1 {
2265+
assumeRoleWithWebIdentity := assumeRoleWithWebIdentityList[0].(map[string]interface{})
2266+
assumeRoleWebIdentityToken = assumeRoleWithWebIdentity["web_identity_token"].(string)
2267+
assumeRoleArn = assumeRoleWithWebIdentity["role_arn"].(string)
2268+
assumeRoleSessionName = assumeRoleWithWebIdentity["session_name"].(string)
2269+
assumeRoleSessionDuration = assumeRoleWithWebIdentity["session_duration"].(int)
2270+
2271+
_ = genClientWithOidcSTS(&tcClient, assumeRoleArn, assumeRoleSessionName, assumeRoleSessionDuration, assumeRoleWebIdentityToken)
2272+
needSecret = false
2273+
}
2274+
}
2275+
2276+
if needSecret && (secretId == "" || secretKey == "") {
2277+
return nil, fmt.Errorf("Please set your `secret_id` and `secret_key`.\n")
21292278
}
21302279

21312280
return &tcClient, nil
@@ -2157,6 +2306,60 @@ func genClientWithSTS(tcClient *TencentCloudClient, assumeRoleArn, assumeRoleSes
21572306
return nil
21582307
}
21592308

2309+
func genClientWithSamlSTS(tcClient *TencentCloudClient, assumeRoleArn, assumeRoleSessionName string, assumeRoleSessionDuration int, assumeRoleSamlAssertion, assumeRolePrincipalArn string) error {
2310+
// applying STS credentials
2311+
request := sdksts.NewAssumeRoleWithSAMLRequest()
2312+
request.RoleArn = helper.String(assumeRoleArn)
2313+
request.RoleSessionName = helper.String(assumeRoleSessionName)
2314+
request.DurationSeconds = helper.IntUint64(assumeRoleSessionDuration)
2315+
request.SAMLAssertion = helper.String(assumeRoleSamlAssertion)
2316+
request.PrincipalArn = helper.String(assumeRolePrincipalArn)
2317+
2318+
ratelimit.Check(request.GetAction())
2319+
var stsExtInfo connectivity.StsExtInfo
2320+
stsExtInfo.Authorization = "SKIP"
2321+
response, err := tcClient.apiV3Conn.UseStsClient(stsExtInfo).AssumeRoleWithSAML(request)
2322+
if err != nil {
2323+
return err
2324+
}
2325+
2326+
// using STS credentials
2327+
tcClient.apiV3Conn.Credential = sdkcommon.NewTokenCredential(
2328+
*response.Response.Credentials.TmpSecretId,
2329+
*response.Response.Credentials.TmpSecretKey,
2330+
*response.Response.Credentials.Token,
2331+
)
2332+
2333+
return nil
2334+
}
2335+
2336+
func genClientWithOidcSTS(tcClient *TencentCloudClient, assumeRoleArn, assumeRoleSessionName string, assumeRoleSessionDuration int, assumeRolePolicy string) error {
2337+
// applying STS credentials
2338+
request := sdksts.NewAssumeRoleWithWebIdentityRequest()
2339+
request.ProviderId = helper.String("OIDC")
2340+
request.RoleArn = helper.String(assumeRoleArn)
2341+
request.RoleSessionName = helper.String(assumeRoleSessionName)
2342+
request.DurationSeconds = helper.IntInt64(assumeRoleSessionDuration)
2343+
request.WebIdentityToken = helper.String(assumeRolePolicy)
2344+
2345+
ratelimit.Check(request.GetAction())
2346+
var stsExtInfo connectivity.StsExtInfo
2347+
stsExtInfo.Authorization = "SKIP"
2348+
response, err := tcClient.apiV3Conn.UseStsClient(stsExtInfo).AssumeRoleWithWebIdentity(request)
2349+
if err != nil {
2350+
return err
2351+
}
2352+
2353+
// using STS credentials
2354+
tcClient.apiV3Conn.Credential = sdkcommon.NewTokenCredential(
2355+
*response.Response.Credentials.TmpSecretId,
2356+
*response.Response.Credentials.TmpSecretKey,
2357+
*response.Response.Credentials.Token,
2358+
)
2359+
2360+
return nil
2361+
}
2362+
21602363
var providerConfig map[string]interface{}
21612364

21622365
func getConfigFromProfile(d *schema.ResourceData, ProfileKey string) (interface{}, error) {

0 commit comments

Comments
 (0)