Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: aws_s3_account_public_access_block #6851

Merged
merged 1 commit into from
Dec 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import (
"github.com/aws/aws-sdk-go/service/redshift"
"github.com/aws/aws-sdk-go/service/route53"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3control"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/aws/aws-sdk-go/service/securityhub"
"github.com/aws/aws-sdk-go/service/servicecatalog"
Expand Down Expand Up @@ -150,6 +151,7 @@ type Config struct {
RdsEndpoint string
R53Endpoint string
S3Endpoint string
S3ControlEndpoint string
SnsEndpoint string
SqsEndpoint string
StsEndpoint string
Expand Down Expand Up @@ -198,6 +200,7 @@ type AWSClient struct {
appautoscalingconn *applicationautoscaling.ApplicationAutoScaling
autoscalingconn *autoscaling.AutoScaling
s3conn *s3.S3
s3controlconn *s3control.S3Control
secretsmanagerconn *secretsmanager.SecretsManager
securityhubconn *securityhub.SecurityHub
scconn *servicecatalog.ServiceCatalog
Expand Down Expand Up @@ -433,6 +436,7 @@ func (c *Config) Client() (interface{}, error) {
awsKmsSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.KmsEndpoint)})
awsRdsSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.RdsEndpoint)})
awsS3Sess := sess.Copy(&aws.Config{Endpoint: aws.String(c.S3Endpoint)})
awsS3ControlSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.S3ControlEndpoint)})
awsSnsSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.SnsEndpoint)})
awsSqsSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.SqsEndpoint)})
awsStsSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.StsEndpoint)})
Expand Down Expand Up @@ -567,6 +571,7 @@ func (c *Config) Client() (interface{}, error) {
client.redshiftconn = redshift.New(sess)
client.simpledbconn = simpledb.New(sess)
client.s3conn = s3.New(awsS3Sess)
client.s3controlconn = s3control.New(awsS3ControlSess)
client.scconn = servicecatalog.New(sess)
client.sdconn = servicediscovery.New(sess)
client.sesConn = ses.New(sess)
Expand Down
10 changes: 10 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ func Provider() terraform.ResourceProvider {
"aws_ses_event_destination": resourceAwsSesEventDestination(),
"aws_ses_identity_notification_topic": resourceAwsSesNotificationTopic(),
"aws_ses_template": resourceAwsSesTemplate(),
"aws_s3_account_public_access_block": resourceAwsS3AccountPublicAccessBlock(),
"aws_s3_bucket": resourceAwsS3Bucket(),
"aws_s3_bucket_policy": resourceAwsS3BucketPolicy(),
"aws_s3_bucket_object": resourceAwsS3BucketObject(),
Expand Down Expand Up @@ -812,6 +813,8 @@ func init() {

"s3_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

"s3control_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

"sns_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",

"sqs_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n",
Expand Down Expand Up @@ -923,6 +926,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
config.R53Endpoint = endpoints["r53"].(string)
config.RdsEndpoint = endpoints["rds"].(string)
config.S3Endpoint = endpoints["s3"].(string)
config.S3ControlEndpoint = endpoints["s3control"].(string)
config.SnsEndpoint = endpoints["sns"].(string)
config.SqsEndpoint = endpoints["sqs"].(string)
config.StsEndpoint = endpoints["sts"].(string)
Expand Down Expand Up @@ -1128,6 +1132,12 @@ func endpointsSchema() *schema.Schema {
Default: "",
Description: descriptions["s3_endpoint"],
},
"s3control": {
Type: schema.TypeString,
Optional: true,
Default: "",
Description: descriptions["s3control_endpoint"],
},
"sns": {
Type: schema.TypeString,
Optional: true,
Expand Down
182 changes: 182 additions & 0 deletions aws/resource_aws_s3_account_public_access_block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package aws

import (
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3control"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsS3AccountPublicAccessBlock() *schema.Resource {
return &schema.Resource{
Create: resourceAwsS3AccountPublicAccessBlockCreate,
Read: resourceAwsS3AccountPublicAccessBlockRead,
Update: resourceAwsS3AccountPublicAccessBlockUpdate,
Delete: resourceAwsS3AccountPublicAccessBlockDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validateAwsAccountId,
},
"block_public_acls": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"block_public_policy": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"ignore_public_acls": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"restrict_public_buckets": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}

func resourceAwsS3AccountPublicAccessBlockCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

accountID := meta.(*AWSClient).accountid
if v, ok := d.GetOk("account_id"); ok {
accountID = v.(string)
}

input := &s3control.PutPublicAccessBlockInput{
AccountId: aws.String(accountID),
PublicAccessBlockConfiguration: &s3control.PublicAccessBlockConfiguration{
BlockPublicAcls: aws.Bool(d.Get("block_public_acls").(bool)),
BlockPublicPolicy: aws.Bool(d.Get("block_public_policy").(bool)),
IgnorePublicAcls: aws.Bool(d.Get("ignore_public_acls").(bool)),
RestrictPublicBuckets: aws.Bool(d.Get("restrict_public_buckets").(bool)),
},
}

log.Printf("[DEBUG] Creating S3 Account Public Access Block: %s", input)
_, err := conn.PutPublicAccessBlock(input)
if err != nil {
return fmt.Errorf("error creating S3 Account Public Access Block: %s", err)
}

d.SetId(accountID)

return resourceAwsS3AccountPublicAccessBlockRead(d, meta)
}

func resourceAwsS3AccountPublicAccessBlockRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

input := &s3control.GetPublicAccessBlockInput{
AccountId: aws.String(d.Id()),
}

// Retry for eventual consistency on creation
var output *s3control.GetPublicAccessBlockOutput
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
var err error
output, err = conn.GetPublicAccessBlock(input)

if d.IsNewResource() && isAWSErr(err, s3control.ErrCodeNoSuchPublicAccessBlockConfiguration, "") {
return resource.RetryableError(err)
}

if err != nil {
return resource.NonRetryableError(err)
}

return nil
})

if isAWSErr(err, s3control.ErrCodeNoSuchPublicAccessBlockConfiguration, "") {
log.Printf("[WARN] S3 Account Public Access Block (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading S3 Account Public Access Block: %s", err)
}

if output == nil || output.PublicAccessBlockConfiguration == nil {
return fmt.Errorf("error reading S3 Account Public Access Block (%s): missing public access block configuration", d.Id())
}

d.Set("account_id", d.Id())
d.Set("block_public_acls", output.PublicAccessBlockConfiguration.BlockPublicAcls)
d.Set("block_public_policy", output.PublicAccessBlockConfiguration.BlockPublicPolicy)
d.Set("ignore_public_acls", output.PublicAccessBlockConfiguration.IgnorePublicAcls)
d.Set("restrict_public_buckets", output.PublicAccessBlockConfiguration.RestrictPublicBuckets)

return nil
}

func resourceAwsS3AccountPublicAccessBlockUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

input := &s3control.PutPublicAccessBlockInput{
AccountId: aws.String(d.Id()),
PublicAccessBlockConfiguration: &s3control.PublicAccessBlockConfiguration{
BlockPublicAcls: aws.Bool(d.Get("block_public_acls").(bool)),
BlockPublicPolicy: aws.Bool(d.Get("block_public_policy").(bool)),
IgnorePublicAcls: aws.Bool(d.Get("ignore_public_acls").(bool)),
RestrictPublicBuckets: aws.Bool(d.Get("restrict_public_buckets").(bool)),
},
}

log.Printf("[DEBUG] Updating S3 Account Public Access Block: %s", input)
_, err := conn.PutPublicAccessBlock(input)
if err != nil {
return fmt.Errorf("error updating S3 Account Public Access Block (%s): %s", d.Id(), err)
}

// Workaround API eventual consistency issues. This type of logic should not normally be used.
// We cannot reliably determine when the Read after Update might be properly updated.
// Rather than introduce complicated retry logic, we presume that a lack of an update error
// means our update succeeded with our expected values.
d.Set("block_public_acls", input.PublicAccessBlockConfiguration.BlockPublicAcls)
d.Set("block_public_policy", input.PublicAccessBlockConfiguration.BlockPublicPolicy)
d.Set("ignore_public_acls", input.PublicAccessBlockConfiguration.IgnorePublicAcls)
d.Set("restrict_public_buckets", input.PublicAccessBlockConfiguration.RestrictPublicBuckets)

// Skip normal Read after Update due to eventual consistency issues
return nil
}

func resourceAwsS3AccountPublicAccessBlockDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

input := &s3control.DeletePublicAccessBlockInput{
AccountId: aws.String(d.Id()),
}

_, err := conn.DeletePublicAccessBlock(input)

if isAWSErr(err, s3control.ErrCodeNoSuchPublicAccessBlockConfiguration, "") {
return nil
}

if err != nil {
return fmt.Errorf("error deleting S3 Account Public Access Block (%s): %s", d.Id(), err)
}

return nil
}
Loading