github.com/pdecat/terraform@v0.11.9-beta1/backend/remote-state/s3/backend.go (about)

     1  package s3
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/aws/aws-sdk-go/service/dynamodb"
     9  	"github.com/aws/aws-sdk-go/service/s3"
    10  	"github.com/hashicorp/terraform/backend"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  
    13  	terraformAWS "github.com/terraform-providers/terraform-provider-aws/aws"
    14  )
    15  
    16  // New creates a new backend for S3 remote state.
    17  func New() backend.Backend {
    18  	s := &schema.Backend{
    19  		Schema: map[string]*schema.Schema{
    20  			"bucket": {
    21  				Type:        schema.TypeString,
    22  				Required:    true,
    23  				Description: "The name of the S3 bucket",
    24  			},
    25  
    26  			"key": {
    27  				Type:        schema.TypeString,
    28  				Required:    true,
    29  				Description: "The path to the state file inside the bucket",
    30  				ValidateFunc: func(v interface{}, s string) ([]string, []error) {
    31  					// s3 will strip leading slashes from an object, so while this will
    32  					// technically be accepted by s3, it will break our workspace hierarchy.
    33  					if strings.HasPrefix(v.(string), "/") {
    34  						return nil, []error{fmt.Errorf("key must not start with '/'")}
    35  					}
    36  					return nil, nil
    37  				},
    38  			},
    39  
    40  			"region": {
    41  				Type:        schema.TypeString,
    42  				Required:    true,
    43  				Description: "The region of the S3 bucket.",
    44  				DefaultFunc: schema.EnvDefaultFunc("AWS_DEFAULT_REGION", nil),
    45  			},
    46  
    47  			"endpoint": {
    48  				Type:        schema.TypeString,
    49  				Optional:    true,
    50  				Description: "A custom endpoint for the S3 API",
    51  				DefaultFunc: schema.EnvDefaultFunc("AWS_S3_ENDPOINT", ""),
    52  			},
    53  
    54  			"encrypt": {
    55  				Type:        schema.TypeBool,
    56  				Optional:    true,
    57  				Description: "Whether to enable server side encryption of the state file",
    58  				Default:     false,
    59  			},
    60  
    61  			"acl": {
    62  				Type:        schema.TypeString,
    63  				Optional:    true,
    64  				Description: "Canned ACL to be applied to the state file",
    65  				Default:     "",
    66  			},
    67  
    68  			"access_key": {
    69  				Type:        schema.TypeString,
    70  				Optional:    true,
    71  				Description: "AWS access key",
    72  				Default:     "",
    73  			},
    74  
    75  			"secret_key": {
    76  				Type:        schema.TypeString,
    77  				Optional:    true,
    78  				Description: "AWS secret key",
    79  				Default:     "",
    80  			},
    81  
    82  			"kms_key_id": {
    83  				Type:        schema.TypeString,
    84  				Optional:    true,
    85  				Description: "The ARN of a KMS Key to use for encrypting the state",
    86  				Default:     "",
    87  			},
    88  
    89  			"lock_table": {
    90  				Type:        schema.TypeString,
    91  				Optional:    true,
    92  				Description: "DynamoDB table for state locking",
    93  				Default:     "",
    94  				Deprecated:  "please use the dynamodb_table attribute",
    95  			},
    96  
    97  			"dynamodb_table": {
    98  				Type:        schema.TypeString,
    99  				Optional:    true,
   100  				Description: "DynamoDB table for state locking and consistency",
   101  				Default:     "",
   102  			},
   103  
   104  			"profile": {
   105  				Type:        schema.TypeString,
   106  				Optional:    true,
   107  				Description: "AWS profile name",
   108  				Default:     "",
   109  			},
   110  
   111  			"shared_credentials_file": {
   112  				Type:        schema.TypeString,
   113  				Optional:    true,
   114  				Description: "Path to a shared credentials file",
   115  				Default:     "",
   116  			},
   117  
   118  			"token": {
   119  				Type:        schema.TypeString,
   120  				Optional:    true,
   121  				Description: "MFA token",
   122  				Default:     "",
   123  			},
   124  
   125  			"skip_credentials_validation": {
   126  				Type:        schema.TypeBool,
   127  				Optional:    true,
   128  				Description: "Skip the credentials validation via STS API.",
   129  				Default:     false,
   130  			},
   131  
   132  			"skip_get_ec2_platforms": {
   133  				Type:        schema.TypeBool,
   134  				Optional:    true,
   135  				Description: "Skip getting the supported EC2 platforms.",
   136  				Default:     false,
   137  			},
   138  
   139  			"skip_region_validation": {
   140  				Type:        schema.TypeBool,
   141  				Optional:    true,
   142  				Description: "Skip static validation of region name.",
   143  				Default:     false,
   144  			},
   145  
   146  			"skip_requesting_account_id": {
   147  				Type:        schema.TypeBool,
   148  				Optional:    true,
   149  				Description: "Skip requesting the account ID.",
   150  				Default:     false,
   151  			},
   152  
   153  			"skip_metadata_api_check": {
   154  				Type:        schema.TypeBool,
   155  				Optional:    true,
   156  				Description: "Skip the AWS Metadata API check.",
   157  				Default:     false,
   158  			},
   159  
   160  			"role_arn": {
   161  				Type:        schema.TypeString,
   162  				Optional:    true,
   163  				Description: "The role to be assumed",
   164  				Default:     "",
   165  			},
   166  
   167  			"session_name": {
   168  				Type:        schema.TypeString,
   169  				Optional:    true,
   170  				Description: "The session name to use when assuming the role.",
   171  				Default:     "",
   172  			},
   173  
   174  			"external_id": {
   175  				Type:        schema.TypeString,
   176  				Optional:    true,
   177  				Description: "The external ID to use when assuming the role",
   178  				Default:     "",
   179  			},
   180  
   181  			"assume_role_policy": {
   182  				Type:        schema.TypeString,
   183  				Optional:    true,
   184  				Description: "The permissions applied when assuming a role.",
   185  				Default:     "",
   186  			},
   187  
   188  			"workspace_key_prefix": {
   189  				Type:        schema.TypeString,
   190  				Optional:    true,
   191  				Description: "The prefix applied to the non-default state path inside the bucket",
   192  				Default:     "env:",
   193  			},
   194  
   195  			"force_path_style": {
   196  				Type:        schema.TypeBool,
   197  				Optional:    true,
   198  				Description: "Force s3 to use path style api.",
   199  				Default:     false,
   200  			},
   201  		},
   202  	}
   203  
   204  	result := &Backend{Backend: s}
   205  	result.Backend.ConfigureFunc = result.configure
   206  	return result
   207  }
   208  
   209  type Backend struct {
   210  	*schema.Backend
   211  
   212  	// The fields below are set from configure
   213  	s3Client  *s3.S3
   214  	dynClient *dynamodb.DynamoDB
   215  
   216  	bucketName           string
   217  	keyName              string
   218  	serverSideEncryption bool
   219  	acl                  string
   220  	kmsKeyID             string
   221  	ddbTable             string
   222  	workspaceKeyPrefix   string
   223  }
   224  
   225  func (b *Backend) configure(ctx context.Context) error {
   226  	if b.s3Client != nil {
   227  		return nil
   228  	}
   229  
   230  	// Grab the resource data
   231  	data := schema.FromContextBackendConfig(ctx)
   232  
   233  	b.bucketName = data.Get("bucket").(string)
   234  	b.keyName = data.Get("key").(string)
   235  	b.serverSideEncryption = data.Get("encrypt").(bool)
   236  	b.acl = data.Get("acl").(string)
   237  	b.kmsKeyID = data.Get("kms_key_id").(string)
   238  	b.workspaceKeyPrefix = data.Get("workspace_key_prefix").(string)
   239  
   240  	b.ddbTable = data.Get("dynamodb_table").(string)
   241  	if b.ddbTable == "" {
   242  		// try the deprecated field
   243  		b.ddbTable = data.Get("lock_table").(string)
   244  	}
   245  
   246  	cfg := &terraformAWS.Config{
   247  		AccessKey:               data.Get("access_key").(string),
   248  		AssumeRoleARN:           data.Get("role_arn").(string),
   249  		AssumeRoleExternalID:    data.Get("external_id").(string),
   250  		AssumeRolePolicy:        data.Get("assume_role_policy").(string),
   251  		AssumeRoleSessionName:   data.Get("session_name").(string),
   252  		CredsFilename:           data.Get("shared_credentials_file").(string),
   253  		Profile:                 data.Get("profile").(string),
   254  		Region:                  data.Get("region").(string),
   255  		S3Endpoint:              data.Get("endpoint").(string),
   256  		SecretKey:               data.Get("secret_key").(string),
   257  		Token:                   data.Get("token").(string),
   258  		SkipCredsValidation:     data.Get("skip_credentials_validation").(bool),
   259  		SkipGetEC2Platforms:     data.Get("skip_get_ec2_platforms").(bool),
   260  		SkipRegionValidation:    data.Get("skip_region_validation").(bool),
   261  		SkipRequestingAccountId: data.Get("skip_requesting_account_id").(bool),
   262  		SkipMetadataApiCheck:    data.Get("skip_metadata_api_check").(bool),
   263  		S3ForcePathStyle:        data.Get("force_path_style").(bool),
   264  	}
   265  
   266  	client, err := cfg.Client()
   267  	if err != nil {
   268  		return err
   269  	}
   270  
   271  	b.s3Client = client.(*terraformAWS.AWSClient).S3()
   272  	b.dynClient = client.(*terraformAWS.AWSClient).DynamoDB()
   273  
   274  	return nil
   275  }