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 }