github.com/hooklift/terraform@v0.11.0-beta1.0.20171117000744-6786c1361ffe/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_requesting_account_id": { 140 Type: schema.TypeBool, 141 Optional: true, 142 Description: "Skip requesting the account ID.", 143 Default: false, 144 }, 145 146 "skip_metadata_api_check": { 147 Type: schema.TypeBool, 148 Optional: true, 149 Description: "Skip the AWS Metadata API check.", 150 Default: false, 151 }, 152 153 "role_arn": { 154 Type: schema.TypeString, 155 Optional: true, 156 Description: "The role to be assumed", 157 Default: "", 158 }, 159 160 "session_name": { 161 Type: schema.TypeString, 162 Optional: true, 163 Description: "The session name to use when assuming the role.", 164 Default: "", 165 }, 166 167 "external_id": { 168 Type: schema.TypeString, 169 Optional: true, 170 Description: "The external ID to use when assuming the role", 171 Default: "", 172 }, 173 174 "assume_role_policy": { 175 Type: schema.TypeString, 176 Optional: true, 177 Description: "The permissions applied when assuming a role.", 178 Default: "", 179 }, 180 181 "workspace_key_prefix": { 182 Type: schema.TypeString, 183 Optional: true, 184 Description: "The prefix applied to the non-default state path inside the bucket", 185 Default: "env:", 186 }, 187 }, 188 } 189 190 result := &Backend{Backend: s} 191 result.Backend.ConfigureFunc = result.configure 192 return result 193 } 194 195 type Backend struct { 196 *schema.Backend 197 198 // The fields below are set from configure 199 s3Client *s3.S3 200 dynClient *dynamodb.DynamoDB 201 202 bucketName string 203 keyName string 204 serverSideEncryption bool 205 acl string 206 kmsKeyID string 207 ddbTable string 208 workspaceKeyPrefix string 209 } 210 211 func (b *Backend) configure(ctx context.Context) error { 212 if b.s3Client != nil { 213 return nil 214 } 215 216 // Grab the resource data 217 data := schema.FromContextBackendConfig(ctx) 218 219 b.bucketName = data.Get("bucket").(string) 220 b.keyName = data.Get("key").(string) 221 b.serverSideEncryption = data.Get("encrypt").(bool) 222 b.acl = data.Get("acl").(string) 223 b.kmsKeyID = data.Get("kms_key_id").(string) 224 b.workspaceKeyPrefix = data.Get("workspace_key_prefix").(string) 225 226 b.ddbTable = data.Get("dynamodb_table").(string) 227 if b.ddbTable == "" { 228 // try the depracted field 229 b.ddbTable = data.Get("lock_table").(string) 230 } 231 232 cfg := &terraformAWS.Config{ 233 AccessKey: data.Get("access_key").(string), 234 AssumeRoleARN: data.Get("role_arn").(string), 235 AssumeRoleExternalID: data.Get("external_id").(string), 236 AssumeRolePolicy: data.Get("assume_role_policy").(string), 237 AssumeRoleSessionName: data.Get("session_name").(string), 238 CredsFilename: data.Get("shared_credentials_file").(string), 239 Profile: data.Get("profile").(string), 240 Region: data.Get("region").(string), 241 S3Endpoint: data.Get("endpoint").(string), 242 SecretKey: data.Get("secret_key").(string), 243 Token: data.Get("token").(string), 244 SkipCredsValidation: data.Get("skip_credentials_validation").(bool), 245 SkipGetEC2Platforms: data.Get("skip_get_ec2_platforms").(bool), 246 SkipRequestingAccountId: data.Get("skip_requesting_account_id").(bool), 247 SkipMetadataApiCheck: data.Get("skip_metadata_api_check").(bool), 248 } 249 250 client, err := cfg.Client() 251 if err != nil { 252 return err 253 } 254 255 b.s3Client = client.(*terraformAWS.AWSClient).S3() 256 b.dynClient = client.(*terraformAWS.AWSClient).DynamoDB() 257 258 return nil 259 }