Merge pull request #29307 from hayorov/main

Flatten `assume_role` block for OSS backend
This commit is contained in:
James Bardin 2021-11-01 09:18:25 -04:00 committed by GitHub
commit 2ebdc099ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 262 additions and 213 deletions

View File

@ -24,155 +24,22 @@ import (
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
"github.com/hashicorp/go-cleanhttp"
"github.com/jmespath/go-jmespath"
"github.com/mitchellh/go-homedir"
"github.com/hashicorp/terraform/internal/backend"
"github.com/hashicorp/terraform/internal/legacy/helper/schema"
"github.com/hashicorp/terraform/version"
"github.com/jmespath/go-jmespath"
"github.com/mitchellh/go-homedir"
)
// New creates a new backend for OSS remote state.
func New() backend.Backend {
s := &schema.Backend{
Schema: map[string]*schema.Schema{
"access_key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Alibaba Cloud Access Key ID",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ACCESS_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_ID")),
},
"secret_key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Alibaba Cloud Access Secret Key",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECRET_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_SECRET")),
},
"security_token": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Alibaba Cloud Security Token",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECURITY_TOKEN", ""),
},
"ecs_role_name": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ECS_ROLE_NAME", os.Getenv("ALICLOUD_ECS_ROLE_NAME")),
Description: "The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control' section of the Alibaba Cloud console.",
},
"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "The region of the OSS bucket.",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", os.Getenv("ALICLOUD_DEFAULT_REGION")),
},
"tablestore_endpoint": {
Type: schema.TypeString,
Optional: true,
Description: "A custom endpoint for the TableStore API",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_TABLESTORE_ENDPOINT", ""),
},
"endpoint": {
Type: schema.TypeString,
Optional: true,
Description: "A custom endpoint for the OSS API",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_OSS_ENDPOINT", os.Getenv("OSS_ENDPOINT")),
},
"bucket": &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "The name of the OSS bucket",
},
"prefix": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "The directory where state files will be saved inside the bucket",
Default: "env:",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
prefix := v.(string)
if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") {
return nil, []error{fmt.Errorf("workspace_key_prefix must not start with '/' or './'")}
}
return nil, nil
},
},
"key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "The path of the state file inside the bucket",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
if strings.HasPrefix(v.(string), "/") || strings.HasSuffix(v.(string), "/") {
return nil, []error{fmt.Errorf("key can not start and end with '/'")}
}
return nil, nil
},
Default: "terraform.tfstate",
},
"tablestore_table": {
Type: schema.TypeString,
Optional: true,
Description: "TableStore table for state locking and consistency",
Default: "",
},
"encrypt": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable server side encryption of the state file",
Default: false,
},
"acl": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "Object ACL to be applied to the state file",
Default: "",
ValidateFunc: func(v interface{}, k string) ([]string, []error) {
if value := v.(string); value != "" {
acls := oss.ACLType(value)
if acls != oss.ACLPrivate && acls != oss.ACLPublicRead && acls != oss.ACLPublicReadWrite {
return nil, []error{fmt.Errorf(
"%q must be a valid ACL value , expected %s, %s or %s, got %q",
k, oss.ACLPrivate, oss.ACLPublicRead, oss.ACLPublicReadWrite, acls)}
}
}
return nil, nil
},
},
"assume_role": assumeRoleSchema(),
"shared_credentials_file": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SHARED_CREDENTIALS_FILE", ""),
Description: "This is the path to the shared credentials file. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used.",
},
"profile": {
Type: schema.TypeString,
Optional: true,
Description: "This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable.",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_PROFILE", ""),
},
},
}
result := &Backend{Backend: s}
result.Backend.ConfigureFunc = result.configure
return result
}
func assumeRoleSchema() *schema.Schema {
// Deprecated in favor of flattening assume_role_* options
func deprecatedAssumeRoleSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeSet,
Optional: true,
ConflictsWith: []string{"assume_role_role_arn", "assume_role_session_name", "assume_role_policy", "assume_role_session_expiration"},
MaxItems: 1,
Deprecated: "use assume_role_* options instead",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"role_arn": {
@ -216,6 +83,182 @@ func assumeRoleSchema() *schema.Schema {
}
}
// New creates a new backend for OSS remote state.
func New() backend.Backend {
s := &schema.Backend{
Schema: map[string]*schema.Schema{
"access_key": {
Type: schema.TypeString,
Optional: true,
Description: "Alibaba Cloud Access Key ID",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ACCESS_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_ID")),
},
"secret_key": {
Type: schema.TypeString,
Optional: true,
Description: "Alibaba Cloud Access Secret Key",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECRET_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_SECRET")),
},
"security_token": {
Type: schema.TypeString,
Optional: true,
Description: "Alibaba Cloud Security Token",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECURITY_TOKEN", ""),
},
"ecs_role_name": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ECS_ROLE_NAME", os.Getenv("ALICLOUD_ECS_ROLE_NAME")),
Description: "The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control' section of the Alibaba Cloud console.",
},
"region": {
Type: schema.TypeString,
Optional: true,
Description: "The region of the OSS bucket.",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", os.Getenv("ALICLOUD_DEFAULT_REGION")),
},
"tablestore_endpoint": {
Type: schema.TypeString,
Optional: true,
Description: "A custom endpoint for the TableStore API",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_TABLESTORE_ENDPOINT", ""),
},
"endpoint": {
Type: schema.TypeString,
Optional: true,
Description: "A custom endpoint for the OSS API",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_OSS_ENDPOINT", os.Getenv("OSS_ENDPOINT")),
},
"bucket": {
Type: schema.TypeString,
Required: true,
Description: "The name of the OSS bucket",
},
"prefix": {
Type: schema.TypeString,
Optional: true,
Description: "The directory where state files will be saved inside the bucket",
Default: "env:",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
prefix := v.(string)
if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") {
return nil, []error{fmt.Errorf("workspace_key_prefix must not start with '/' or './'")}
}
return nil, nil
},
},
"key": {
Type: schema.TypeString,
Optional: true,
Description: "The path of the state file inside the bucket",
ValidateFunc: func(v interface{}, s string) ([]string, []error) {
if strings.HasPrefix(v.(string), "/") || strings.HasSuffix(v.(string), "/") {
return nil, []error{fmt.Errorf("key can not start and end with '/'")}
}
return nil, nil
},
Default: "terraform.tfstate",
},
"tablestore_table": {
Type: schema.TypeString,
Optional: true,
Description: "TableStore table for state locking and consistency",
Default: "",
},
"encrypt": {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable server side encryption of the state file",
Default: false,
},
"acl": {
Type: schema.TypeString,
Optional: true,
Description: "Object ACL to be applied to the state file",
Default: "",
ValidateFunc: func(v interface{}, k string) ([]string, []error) {
if value := v.(string); value != "" {
acls := oss.ACLType(value)
if acls != oss.ACLPrivate && acls != oss.ACLPublicRead && acls != oss.ACLPublicReadWrite {
return nil, []error{fmt.Errorf(
"%q must be a valid ACL value , expected %s, %s or %s, got %q",
k, oss.ACLPrivate, oss.ACLPublicRead, oss.ACLPublicReadWrite, acls)}
}
}
return nil, nil
},
},
"shared_credentials_file": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SHARED_CREDENTIALS_FILE", ""),
Description: "This is the path to the shared credentials file. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used.",
},
"profile": {
Type: schema.TypeString,
Optional: true,
Description: "This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable.",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_PROFILE", ""),
},
"assume_role": deprecatedAssumeRoleSchema(),
"assume_role_role_arn": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"assume_role"},
Description: "The ARN of a RAM role to assume prior to making API calls.",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_ARN", ""),
},
"assume_role_session_name": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"assume_role"},
Description: "The session name to use when assuming the role.",
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_SESSION_NAME", ""),
},
"assume_role_policy": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"assume_role"},
Description: "The permissions applied when assuming a role. You cannot use this policy to grant permissions which exceed those of the role that is being assumed.",
},
"assume_role_session_expiration": {
Type: schema.TypeInt,
Optional: true,
ConflictsWith: []string{"assume_role"},
Description: "The time after which the established session for assuming role expires.",
ValidateFunc: func(v interface{}, k string) ([]string, []error) {
min := 900
max := 3600
value, ok := v.(int)
if !ok {
return nil, []error{fmt.Errorf("expected type of %s to be int", k)}
}
if value < min || value > max {
return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)}
}
return nil, nil
},
},
},
}
result := &Backend{Backend: s}
result.Backend.ConfigureFunc = result.configure
return result
}
type Backend struct {
*schema.Backend
@ -228,7 +271,6 @@ type Backend struct {
stateKey string
serverSideEncryption bool
acl string
endpoint string
otsEndpoint string
otsTable string
}
@ -275,6 +317,7 @@ func (b *Backend) configure(ctx context.Context) error {
}
if v, ok := d.GetOk("assume_role"); ok {
// deprecated assume_role block
for _, v := range v.(*schema.Set).List() {
assumeRole := v.(map[string]interface{})
if assumeRole["role_arn"].(string) != "" {
@ -283,11 +326,19 @@ func (b *Backend) configure(ctx context.Context) error {
if assumeRole["session_name"].(string) != "" {
sessionName = assumeRole["session_name"].(string)
}
policy = assumeRole["policy"].(string)
sessionExpiration = assumeRole["session_expiration"].(int)
}
} else {
roleArn = d.Get("assume_role_role_arn").(string)
sessionName = d.Get("assume_role_session_name").(string)
policy = d.Get("assume_role_policy").(string)
sessionExpiration = d.Get("assume_role_session_expiration").(int)
}
if sessionName == "" {
sessionName = "terraform"
}
policy = assumeRole["policy"].(string)
sessionExpiration = assumeRole["session_expiration"].(int)
if sessionExpiration == 0 {
if v := os.Getenv("ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION"); v != "" {
if expiredSeconds, err := strconv.Atoi(v); err == nil {
@ -298,8 +349,6 @@ func (b *Backend) configure(ctx context.Context) error {
sessionExpiration = 3600
}
}
}
}
if accessKey == "" {
ecsRoleName := getBackendConfig(d.Get("ecs_role_name").(string), "ram_role_name")
@ -372,13 +421,13 @@ func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token,
locationClient, err := location.NewClientWithOptions(region, getSdkConfig(), credentials.NewStsTokenCredential(access_key, secret_key, security_token))
if err != nil {
return nil, fmt.Errorf("Unable to initialize the location client: %#v", err)
return nil, fmt.Errorf("unable to initialize the location client: %#v", err)
}
locationClient.AppendUserAgent(TerraformUA, TerraformVersion)
endpointsResponse, err := locationClient.DescribeEndpoints(args)
if err != nil {
return nil, fmt.Errorf("Describe oss endpoint using region: %#v got an error: %#v.", region, err)
return nil, fmt.Errorf("describe oss endpoint using region: %#v got an error: %#v", region, err)
}
return endpointsResponse, nil
}
@ -468,7 +517,7 @@ func (a *Invoker) Run(f func() error) error {
catcher.RetryCount--
if catcher.RetryCount <= 0 {
return fmt.Errorf("Retry timeout and got an error: %#v.", err)
return fmt.Errorf("retry timeout and got an error: %#v", err)
} else {
time.Sleep(time.Duration(catcher.RetryWaitSeconds) * time.Second)
return a.Run(f)
@ -578,7 +627,7 @@ func getAuthCredentialByEcsRoleName(ecsRoleName string) (accessKey, secretKey, t
response := responses.NewCommonResponse()
err = responses.Unmarshal(response, httpResponse, "")
if err != nil {
err = fmt.Errorf("Unmarshal Ecs sts token response err : %s", err.Error())
err = fmt.Errorf("unmarshal Ecs sts token response err : %s", err.Error())
return
}

View File

@ -3,19 +3,18 @@ package oss
import (
"errors"
"fmt"
"log"
"path"
"sort"
"strings"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
"github.com/hashicorp/terraform/internal/backend"
"github.com/hashicorp/terraform/internal/states"
"github.com/hashicorp/terraform/internal/states/remote"
"github.com/hashicorp/terraform/internal/states/statemgr"
"log"
"path"
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
)
const (
@ -43,7 +42,7 @@ func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
TableName: b.otsTable,
})
if err != nil {
return client, fmt.Errorf("Error describing table store %s: %#v", b.otsTable, err)
return client, fmt.Errorf("error describing table store %s: %#v", b.otsTable, err)
}
}
@ -53,7 +52,7 @@ func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
func (b *Backend) Workspaces() ([]string, error) {
bucket, err := b.ossClient.Bucket(b.bucketName)
if err != nil {
return []string{""}, fmt.Errorf("Error getting bucket: %#v", err)
return []string{""}, fmt.Errorf("error getting bucket: %#v", err)
}
var options []oss.Option
@ -135,7 +134,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
lockInfo.Operation = "init"
lockId, err := client.Lock(lockInfo)
if err != nil {
return nil, fmt.Errorf("Failed to lock OSS state: %s", err)
return nil, fmt.Errorf("failed to lock OSS state: %s", err)
}
// Local helper function so we can call it multiple places

View File

@ -3,22 +3,21 @@ package oss
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"encoding/hex"
"log"
"sync"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
"github.com/hashicorp/go-multierror"
uuid "github.com/hashicorp/go-uuid"
"github.com/pkg/errors"
"github.com/hashicorp/terraform/internal/states/remote"
"github.com/hashicorp/terraform/internal/states/statemgr"
"github.com/pkg/errors"
)
const (
@ -48,8 +47,6 @@ type RemoteClient struct {
lockFile string
serverSideEncryption bool
acl string
info *statemgr.LockInfo
mu sync.Mutex
otsTable string
}
@ -99,7 +96,7 @@ func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
func (c *RemoteClient) Put(data []byte) error {
bucket, err := c.ossClient.Bucket(c.bucketName)
if err != nil {
return fmt.Errorf("Error getting bucket: %#v", err)
return fmt.Errorf("error getting bucket: %#v", err)
}
body := bytes.NewReader(data)
@ -116,7 +113,7 @@ func (c *RemoteClient) Put(data []byte) error {
if body != nil {
if err := bucket.PutObject(c.stateFile, body, options...); err != nil {
return fmt.Errorf("Failed to upload state %s: %#v", c.stateFile, err)
return fmt.Errorf("failed to upload state %s: %#v", c.stateFile, err)
}
}
@ -124,7 +121,7 @@ func (c *RemoteClient) Put(data []byte) error {
if err := c.putMD5(sum[:]); err != nil {
// if this errors out, we unfortunately have to error out altogether,
// since the next Get will inevitably fail.
return fmt.Errorf("Failed to store state MD5: %s", err)
return fmt.Errorf("failed to store state MD5: %s", err)
}
return nil
}
@ -132,13 +129,13 @@ func (c *RemoteClient) Put(data []byte) error {
func (c *RemoteClient) Delete() error {
bucket, err := c.ossClient.Bucket(c.bucketName)
if err != nil {
return fmt.Errorf("Error getting bucket %s: %#v", c.bucketName, err)
return fmt.Errorf("error getting bucket %s: %#v", c.bucketName, err)
}
log.Printf("[DEBUG] Deleting remote state from OSS: %#v", c.stateFile)
if err := bucket.DeleteObject(c.stateFile); err != nil {
return fmt.Errorf("Error deleting state %s: %#v", c.stateFile, err)
return fmt.Errorf("error deleting state %s: %#v", c.stateFile, err)
}
if err := c.deleteMD5(); err != nil {
@ -413,11 +410,11 @@ func (c *RemoteClient) lockPath() string {
func (c *RemoteClient) getObj() (*remote.Payload, error) {
bucket, err := c.ossClient.Bucket(c.bucketName)
if err != nil {
return nil, fmt.Errorf("Error getting bucket %s: %#v", c.bucketName, err)
return nil, fmt.Errorf("error getting bucket %s: %#v", c.bucketName, err)
}
if exist, err := bucket.IsObjectExist(c.stateFile); err != nil {
return nil, fmt.Errorf("Estimating object %s is exist got an error: %#v", c.stateFile, err)
return nil, fmt.Errorf("estimating object %s is exist got an error: %#v", c.stateFile, err)
} else if !exist {
return nil, nil
}
@ -425,12 +422,12 @@ func (c *RemoteClient) getObj() (*remote.Payload, error) {
var options []oss.Option
output, err := bucket.GetObject(c.stateFile, options...)
if err != nil {
return nil, fmt.Errorf("Error getting object: %#v", err)
return nil, fmt.Errorf("error getting object: %#v", err)
}
buf := bytes.NewBuffer(nil)
if _, err := io.Copy(buf, output); err != nil {
return nil, fmt.Errorf("Failed to read remote state: %s", err)
return nil, fmt.Errorf("failed to read remote state: %s", err)
}
sum := md5.Sum(buf.Bytes())
payload := &remote.Payload{
@ -452,5 +449,4 @@ This may be caused by unusually long delays in OSS processing a previous state
update. Please wait for a minute or two and try again. If this problem
persists, and neither OSS nor TableStore are experiencing an outage, you may need
to manually verify the remote state and update the Digest value stored in the
TableStore table to the following value: %x
`
TableStore table to the following value: %x`

View File

@ -95,18 +95,23 @@ The following configuration options or environment variables are supported:
to be applied to the state file.
* `shared_credentials_file` - (Optional, Available in 0.12.8+) This is the path to the shared credentials file. It can also be sourced from the `ALICLOUD_SHARED_CREDENTIALS_FILE` environment variable. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used.
* `profile` - (Optional, Available in 0.12.8+) This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable.
* `assume_role` - (Optional, Available in 0.12.6+) If provided with a role ARN, will attempt to assume this role using the supplied credentials.
* `assume_role_role_arn` - (Optional, Available in 1.1.0+) The ARN of the role to assume. If ARN is set to an empty string, it does not perform role switching. It supports the environment variable `ALICLOUD_ASSUME_ROLE_ARN`.
Terraform executes configuration on account with provided credentials.
* `assume_role_policy` - (Optional, Available in 1.1.0+ A more restrictive policy to apply to the temporary credentials. This gives you a way to further restrict the permissions for the resulting temporary security credentials. You cannot use this policy to grant permissions that exceed those of the role that is being assumed.
* `assume_role_session_name` - (Optional, Available in 1.1.0+) The session name to use when assuming the role. If omitted, 'terraform' is passed to the AssumeRole call as session name. It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_NAME`.
* `assume_role_session_expiration` - (Optional, Available in 1.1.0+ The time after which the established session for assuming role expires. Valid value range: [900-3600] seconds. Default to 3600 (in this case Alibaba Cloud uses its own default value). It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION`.
The nested `assume_role` block supports the following:
* `assume_role` - (**Deprecated as of 1.1.0+**, Available in 0.12.6+) If provided with a role ARN, will attempt to assume this role using the supplied credentials.
* `role_arn` - (Required) The ARN of the role to assume. If ARN is set to an empty string, it does not perform role switching. It supports environment variable `ALICLOUD_ASSUME_ROLE_ARN`.
**Deprecated in favor of flattening assume_role_\* options**
* `role_arn` - (Required) The ARN of the role to assume. If ARN is set to an empty string, it does not perform role switching. It supports the environment variable `ALICLOUD_ASSUME_ROLE_ARN`.
Terraform executes configuration on account with provided credentials.
* `policy` - (Optional) A more restrictive policy to apply to the temporary credentials. This gives you a way to further restrict the permissions for the resulting temporary
security credentials. You cannot use this policy to grant permissions which exceed those of the role that is being assumed.
* `policy` - (Optional) A more restrictive policy to apply to the temporary credentials. This gives you a way to further restrict the permissions for the resulting temporary security credentials. You cannot use this policy to grant permissions that exceed those of the role that is being assumed.
* `session_name` - (Optional) The session name to use when assuming the role. If omitted, 'terraform' is passed to the AssumeRole call as session name. It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_NAME`.
* `session_expiration` - (Optional) The time after which the established session for assuming role expires. Valid value range: [900-3600] seconds. Default to 3600 (in this case Alibaba Cloud use own default value). It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION`.
* `session_expiration` - (Optional) The time after which the established session for assuming role expires. Valid value range: [900-3600] seconds. Default to 3600 (in this case Alibaba Cloud uses its own default value). It supports environment variable `ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION`.
-> **Note:** If you want to store state in the custom OSS endpoint, you can specify a environment variable `OSS_ENDPOINT`, like "oss-cn-beijing-internal.aliyuncs.com"
-> **Note:** If you want to store state in the custom OSS endpoint, you can specify an environment variable `OSS_ENDPOINT`, like "oss-cn-beijing-internal.aliyuncs.com"