├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── main.yml ├── go.mod ├── .dockerignore ├── versions.tf ├── .pre-commit-config.yaml ├── test ├── secure-s3-bucket │ ├── outputs.tf │ ├── variables.tf │ └── main.tf ├── terraform_aws_s3_bucket_test.go └── README.md ├── .gitignore ├── examples ├── README.md └── secure-s3-bucket │ ├── main.tf │ └── README.md ├── outputs.tf ├── CONTRIBUTING.md ├── CHANGELOG.md ├── Makefile ├── variables.tf ├── LICENSE ├── main.tf ├── README.md ├── README.tfdoc.hcl └── go.sum /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mariux @mineiros-io/terraform-service-catalog 2 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mineiros-io/terraform-aws-s3-bucket/v2 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/gruntwork-io/terratest v0.34.0 7 | github.com/stretchr/testify v1.4.0 8 | ) 9 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Idea 2 | .idea 3 | 4 | # Misc 5 | CODEOWNERS 6 | Makefile 7 | README.* 8 | LICENSE 9 | 10 | # Terraform 11 | .terraform 12 | 13 | # Go vendors 14 | vendor 15 | 16 | # Git 17 | #.git required for pre-commit 18 | .gitignore 19 | 20 | # CI 21 | .semaphore 22 | 23 | # Docker 24 | Dockerfile 25 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # SET TERRAFORM AND PROVIDER REQUIREMENTS FOR RUNNING THIS MODULE 3 | # --------------------------------------------------------------------------------------------------------------------- 4 | 5 | terraform { 6 | required_version = ">= 0.12.20, < 2.0" 7 | 8 | required_providers { 9 | aws = ">= 2.51, < 4.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/mineiros-io/pre-commit-hooks 3 | rev: v0.3.1 4 | hooks: 5 | - id: terraform-fmt 6 | - id: terraform-validate 7 | exclude: ^examples|.terraform/ 8 | - id: tflint 9 | - id: golangci-lint 10 | - id: phony-targets 11 | - id: markdown-link-check 12 | args: ['-p'] # When adding the -p flag, markdown-link-check will always with an exit code 0, even if dead links are found 13 | verbose: true # Forces the output of the hook to be printed even when the hook passes. 14 | -------------------------------------------------------------------------------- /test/secure-s3-bucket/outputs.tf: -------------------------------------------------------------------------------- 1 | output "example-app-bucket" { 2 | description = "The outputs of our example app bucket." 3 | value = module.example-app-bucket 4 | } 5 | 6 | output "example-log-bucket" { 7 | description = "The outputs of our example log bucket." 8 | value = module.example-log-bucket 9 | } 10 | 11 | output "example-elb-log-bucket" { 12 | description = "The outputs of our example elb log bucket." 13 | value = module.example-elb-log-bucket 14 | } 15 | 16 | output "example-no-bucket" { 17 | description = "The outputs of our example no bucket." 18 | value = module.example-no-bucket 19 | } 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Let us know about an issue in expected behavior. 4 | labels: bug 5 | --- 6 | ### Module Version 7 | 10 | 11 | ### Module use 12 | 15 | 16 | ```hcl 17 | ... 18 | ``` 19 | 20 | ### Expected Behavior 21 | 24 | 25 | ### Actual Behavior 26 | 29 | 30 | ### Steps to Reproduce 31 | 34 | 35 | ### References 36 | 39 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD Pipeline 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | env: 12 | AWS_SECRET_ACCESS_KEY: ${{ secrets.MINEIROS_TESTING_AWS_SECRET_ACCESS_KEY }} 13 | AWS_ACCESS_KEY_ID: ${{ secrets.MINEIROS_TESTING_AWS_ACCESS_KEY_ID }} 14 | 15 | jobs: 16 | pre-commit: 17 | runs-on: ubuntu-latest 18 | name: Static Analysis 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | - name: Run pre-commit 23 | run: make test/pre-commit 24 | 25 | unit-tests: 26 | runs-on: ubuntu-latest 27 | name: Unit Tests 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v2 31 | - name: Run Unit Tests 32 | run: make test/unit-tests 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | 11 | # Terraform lock 12 | *.terraform 13 | 14 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 15 | # .tfvars files are managed as part of configuration and so should be included in 16 | # version control. 17 | # 18 | # example.tfvars 19 | 20 | # Ignore override files as they are usually used to override resources locally and so 21 | # are not checked in 22 | override.tf 23 | override.tf.json 24 | *_override.tf 25 | *_override.tf.json 26 | 27 | # Include override files you do wish to add to version control using negated pattern 28 | # 29 | # !example_override.tf 30 | 31 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 32 | # example: *tfplan* 33 | 34 | # Go best practices dictate that libraries should not include the vendor directory 35 | vendor 36 | 37 | # IntelliJ files 38 | .idea_modules 39 | *.iml 40 | *.iws 41 | *.ipr 42 | .idea/ 43 | build/ 44 | */build/ 45 | out/ 46 | 47 | # local env 48 | .env 49 | -------------------------------------------------------------------------------- /test/secure-s3-bucket/variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # ENVIRONMENT VARIABLES 3 | # Define these secrets as environment variables 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | # AWS_ACCESS_KEY_ID 7 | # AWS_SECRET_ACCESS_KEY 8 | 9 | # --------------------------------------------------------------------------------------------------------------------- 10 | # REQUIRED VARIABLES 11 | # These variables must be set when using this module. 12 | # --------------------------------------------------------------------------------------------------------------------- 13 | 14 | variable "aws_region" { 15 | description = "The AWS region in which all resources will be created." 16 | type = string 17 | } 18 | 19 | # --------------------------------------------------------------------------------------------------------------------- 20 | # OPTIONAL VARIABLES 21 | # These variables have defaults, but may be overridden. 22 | # --------------------------------------------------------------------------------------------------------------------- 23 | -------------------------------------------------------------------------------- /test/terraform_aws_s3_bucket_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/gruntwork-io/terratest/modules/aws" 7 | "github.com/gruntwork-io/terratest/modules/terraform" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestSecureS3Bucket(t *testing.T) { 12 | t.Parallel() 13 | 14 | awsRegion := aws.GetRandomRegion(t, nil, nil) 15 | 16 | terraformOptions := &terraform.Options{ 17 | // The path to where your Terraform code is located 18 | TerraformDir: "./secure-s3-bucket", 19 | Vars: map[string]interface{}{ 20 | "aws_region": awsRegion, 21 | }, 22 | Upgrade: true, 23 | } 24 | 25 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 26 | defer terraform.Destroy(t, terraformOptions) 27 | 28 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 29 | terraform.InitAndApply(t, terraformOptions) 30 | 31 | stdout := terraform.Plan(t, terraformOptions) 32 | 33 | resourceCount := terraform.GetResourceCount(t, stdout) 34 | assert.Equal(t, 0, resourceCount.Add, "No resources should have been created. Found %d instead.", resourceCount.Add) 35 | assert.Equal(t, 0, resourceCount.Change, "No resources should have been changed. Found %d instead.", resourceCount.Change) 36 | assert.Equal(t, 0, resourceCount.Destroy, "No resources should have been destroyed. Found %d instead.", resourceCount.Destroy) 37 | } 38 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | [][homepage] 2 | 3 | [![GitHub tag (latest SemVer)][badge-semver]][releases-github] 4 | [![license][badge-license]][apache20] 5 | [![Terraform Version][badge-terraform]][releases-terraform] 6 | [![Join Slack][badge-slack]][slack] 7 | 8 | # Examples for using this Mineiros Module 9 | 10 | - [examples/secure-s3-bucket] creates two secure AWS S3-Buckets using the `mineiros-io/terraform-aws-s3-bucket` module. 11 | 12 | 13 | 14 | [examples/secure-s3-bucket]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/examples/secure-s3-bucket 15 | 16 | [homepage]: https://mineiros.io/?ref=terraform-aws-s3-bucket 17 | 18 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 19 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform 20 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 21 | [badge-semver]: https://img.shields.io/github/v/tag/mineiros-io/terraform-aws-s3-bucket.svg?label=latest&sort=semver 22 | 23 | [releases-github]: https://github.com/mineiros-io/terraform-aws-s3-bucket/releases 24 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 25 | [apache20]: https://opensource.org/licenses/Apache-2.0 26 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature. 4 | labels: enhancement 5 | --- 6 | ### Current Version 7 | 10 | 11 | ### Use-cases 12 | 19 | 20 | ### Attempted Solutions 21 | 26 | 27 | ### Proposal 28 | 35 | 36 | ### References 37 | 40 | -------------------------------------------------------------------------------- /examples/secure-s3-bucket/main.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # CREATE TWO SECURE S3 BUCKETS INSIDE THE SAME AWS ACCOUNT 3 | # This example creates a S3 Bucket and another Log S3 Bucket. 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = "us-east-1" 8 | } 9 | 10 | # --------------------------------------------------------------------------------------------------------------------- 11 | # Create the Example App S3 Bucket 12 | # --------------------------------------------------------------------------------------------------------------------- 13 | 14 | module "example-app-bucket" { 15 | source = "mineiros-io/s3-bucket/aws" 16 | version = "~> 0.6.0" 17 | 18 | bucket_prefix = "app" 19 | 20 | access_points = [{ name = "app" }] 21 | 22 | versioning = true 23 | 24 | logging = { 25 | target_bucket = module.example-log-bucket.id 26 | target_prefix = "log/app/" 27 | } 28 | 29 | tags = { 30 | Name = "SPA S3 Bucket" 31 | } 32 | } 33 | 34 | # --------------------------------------------------------------------------------------------------------------------- 35 | # Create the Example Log S3 Bucket 36 | # --------------------------------------------------------------------------------------------------------------------- 37 | 38 | module "example-log-bucket" { 39 | source = "mineiros-io/s3-bucket/aws" 40 | version = "~> 0.6.0" 41 | 42 | bucket_prefix = "log" 43 | 44 | acl = "log-delivery-write" 45 | 46 | # allow elb log delivery from multiple regions 47 | elb_regions = ["us-east-1", "eu-west-1"] 48 | 49 | lifecycle_rules = [ 50 | { 51 | id = "log" 52 | enabled = true 53 | 54 | prefix = "log/" 55 | 56 | tags = { 57 | "rule" = "log" 58 | "autoclean" = "true" 59 | } 60 | 61 | transition = [ 62 | { 63 | days = 30 64 | storage_class = "STANDARD_IA" 65 | }, 66 | { 67 | days = 60 68 | storage_class = "GLACIER" 69 | } 70 | ] 71 | 72 | expiration = { 73 | days = 90 74 | } 75 | } 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # OUTPUT CALCULATED VARIABLES (prefer full objects) 3 | # ------------------------------------------------------------------------------ 4 | output "id" { 5 | description = "The name of the bucket." 6 | value = join("", aws_s3_bucket.bucket.*.id) 7 | } 8 | 9 | output "arn" { 10 | description = "The ARN of the bucket." 11 | value = join("", aws_s3_bucket.bucket.*.arn) 12 | } 13 | 14 | output "bucket_domain_name" { 15 | description = "The domain name of the bucket." 16 | value = join("", aws_s3_bucket.bucket.*.bucket_domain_name) 17 | } 18 | 19 | output "bucket_regional_domain_name" { 20 | description = "The region-specific domain name of the bucket." 21 | value = join("", aws_s3_bucket.bucket.*.bucket_regional_domain_name) 22 | } 23 | 24 | output "hosted_zone_id" { 25 | description = "The Route 53 Hosted Zone ID for this bucket's region." 26 | value = join("", aws_s3_bucket.bucket.*.hosted_zone_id) 27 | } 28 | 29 | output "region" { 30 | description = "The AWS region this bucket resides in." 31 | value = join("", aws_s3_bucket.bucket.*.region) 32 | } 33 | 34 | # ------------------------------------------------------------------------------ 35 | # OUTPUT ALL RESOURCES AS FULL OBJECTS 36 | # ------------------------------------------------------------------------------ 37 | 38 | locals { 39 | 40 | # fix tf13 / aws3 output change detection issues (no github issue) 41 | # terraform detects whitespace only changes in jsonencode() and claims 42 | # changes 43 | o_bucket_policy_policy = try(aws_s3_bucket_policy.bucket[0].policy, "{}") 44 | o_bucket_policy = try(merge(aws_s3_bucket_policy.bucket[0], { 45 | policy = jsonencode(jsondecode(local.o_bucket_policy_policy)) 46 | }), null) 47 | # o_bucket_policy = try(aws_s3_bucket_policy.bucket[0], null) 48 | 49 | # fix tf13 / aws3 output change detection issues (no github issue) 50 | # bucket always detects change in tags out put from null => {} 51 | o_bucket_tags = try(aws_s3_bucket.bucket[0].tags, "{}") 52 | o_bucket = try(merge(aws_s3_bucket.bucket[0], { 53 | tags = local.o_bucket_tags != null ? local.o_bucket_tags : {} 54 | }), null) 55 | } 56 | 57 | output "bucket" { 58 | description = "The full bucket object." 59 | value = local.o_bucket 60 | } 61 | 62 | output "bucket_policy" { 63 | description = "The full bucket object." 64 | value = local.o_bucket_policy 65 | } 66 | 67 | output "origin_access_identity" { 68 | description = "The AWS Cloudfront Origin Access Identity object." 69 | value = try(aws_cloudfront_origin_access_identity.oai[0], {}) 70 | } 71 | 72 | output "access_point" { 73 | description = "A map of acccess points keyed by name." 74 | value = aws_s3_access_point.ap 75 | } 76 | 77 | # ------------------------------------------------------------------------------ 78 | # OUTPUT ALL INPUT VARIABLES AS-IS 79 | # ------------------------------------------------------------------------------ 80 | 81 | # ------------------------------------------------------------------------------ 82 | # OUTPUT MODULE CONFIGURATION 83 | # ------------------------------------------------------------------------------ 84 | 85 | output "module_enabled" { 86 | description = "Whether the module is enabled" 87 | value = var.module_enabled 88 | } 89 | -------------------------------------------------------------------------------- /test/secure-s3-bucket/main.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # CREATE TWO SECURE S3 BUCKETS INSIDE THE SAME AWS ACCOUNT 3 | # This template creates an Example S3 Bucket and another Log S3 Bucket. 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | provider "aws" { 7 | region = var.aws_region 8 | } 9 | 10 | # --------------------------------------------------------------------------------------------------------------------- 11 | # Create the Example App S3 Bucket 12 | # --------------------------------------------------------------------------------------------------------------------- 13 | 14 | module "example-app-bucket" { 15 | source = "../.." 16 | 17 | versioning = true 18 | 19 | logging = { 20 | target_bucket = module.example-log-bucket.id 21 | target_prefix = "log/" 22 | } 23 | 24 | create_origin_access_identity = true 25 | 26 | access_points = [ 27 | { 28 | name = "app" 29 | } 30 | ] 31 | 32 | cors_rule = { 33 | allowed_headers = ["*"] 34 | allowed_methods = ["PUT", "POST"] 35 | allowed_origins = ["https://s3-website-test.mineiros.io"] 36 | expose_headers = ["ETag"] 37 | max_age_seconds = 3000 38 | } 39 | 40 | tags = { 41 | Name = "Just a S3 Bucket" 42 | Environment = "Testing" 43 | } 44 | } 45 | 46 | # --------------------------------------------------------------------------------------------------------------------- 47 | # Create the Example Log S3 Bucket 48 | # --------------------------------------------------------------------------------------------------------------------- 49 | 50 | module "example-log-bucket" { 51 | source = "../.." 52 | 53 | acl = "log-delivery-write" 54 | 55 | # this is just for running the example even if logs already exist 56 | # this should not be set in production as all objects will be unrecoverably destroyed 57 | force_destroy = true 58 | 59 | lifecycle_rules = [ 60 | { 61 | id = "log" 62 | enabled = true 63 | 64 | prefix = "log/" 65 | 66 | tags = { 67 | "rule" = "log" 68 | "autoclean" = "true" 69 | } 70 | 71 | transition = [ 72 | { 73 | days = 30 74 | storage_class = "STANDARD_IA" # or "ONEZONE_IA" 75 | }, 76 | { 77 | days = 60 78 | storage_class = "GLACIER" 79 | } 80 | ] 81 | 82 | expiration = { 83 | days = 90 84 | } 85 | } 86 | ] 87 | } 88 | 89 | # --------------------------------------------------------------------------------------------------------------------- 90 | # Create the Example ELB Log S3 Bucket 91 | # --------------------------------------------------------------------------------------------------------------------- 92 | module "example-elb-log-bucket" { 93 | source = "../.." 94 | 95 | elb_regions = ["us-east-1", "eu-west-1"] 96 | } 97 | 98 | # --------------------------------------------------------------------------------------------------------------------- 99 | # Do not create the bucket 100 | # --------------------------------------------------------------------------------------------------------------------- 101 | module "example-no-bucket" { 102 | source = "../.." 103 | 104 | module_enabled = false 105 | } 106 | -------------------------------------------------------------------------------- /examples/secure-s3-bucket/README.md: -------------------------------------------------------------------------------- 1 | [][homepage] 2 | 3 | [![GitHub tag (latest SemVer)][badge-semver]][releases-github] 4 | [![license][badge-license]][apache20] 5 | [![Terraform Version][badge-terraform]][releases-terraform] 6 | [![Join Slack][badge-slack]][slack] 7 | 8 | # What this example shows 9 | 10 | This code example creates two secure AWS S3-Buckets using the `mineiros-io/terraform-aws-s3-bucket` module. 11 | 12 | One bucket is the `app` bucket which could be used to store a single-page-applications static files. 13 | 14 | The other bucket is a `log` bucket to store access logs from the app bucket and additional logs from 15 | ELBs in two different regions. Lifecycle rules are set up on the log bucket to migrate older logs into 16 | cheaper storage. 17 | 18 | ## Basic usage 19 | The code in [main.tf] defines... 20 | ```hcl 21 | module "example-app-bucket" { 22 | source = "mineiros-io/s3-bucket/aws" 23 | version = "~> 0.6.0" 24 | 25 | bucket_prefix = "app" 26 | 27 | access_points = [{ name = "app" }] 28 | 29 | versioning = true 30 | 31 | logging = { 32 | target_bucket = module.example-log-bucket.id 33 | target_prefix = "log/app/" 34 | } 35 | 36 | tags = { 37 | Name = "SPA S3 Bucket" 38 | } 39 | } 40 | 41 | module "example-log-bucket" { 42 | source = "mineiros-io/s3-bucket/aws" 43 | version = "~> 0.6.0" 44 | 45 | bucket_prefix = "log" 46 | 47 | acl = "log-delivery-write" 48 | 49 | # allow elb log delivery from multiple regions 50 | elb_regions = ["us-east-1", "eu-west-1"] 51 | 52 | lifecycle_rules = [ 53 | { 54 | id = "log" 55 | enabled = true 56 | 57 | prefix = "log/" 58 | 59 | tags = { 60 | "rule" = "log" 61 | "autoclean" = "true" 62 | } 63 | 64 | transition = [ 65 | { 66 | days = 30 67 | storage_class = "STANDARD_IA" 68 | }, 69 | { 70 | days = 60 71 | storage_class = "GLACIER" 72 | } 73 | ] 74 | 75 | expiration = { 76 | days = 90 77 | } 78 | } 79 | ] 80 | } 81 | ``` 82 | 83 | ## Running the example 84 | 85 | ### Cloning the repository 86 | ``` 87 | git clone https://github.com/mineiros-io/terraform-aws-s3-bucket.git 88 | cd terraform-aws-s3-bucket/examples/example 89 | ``` 90 | 91 | ### Initializing Terraform 92 | Run `terraform init` to initialize the example. The output should look like: 93 | 94 | ### Applying the example 95 | Run `terraform apply -auto-approve` to create the resources. 96 | 97 | ### Destroying the example 98 | Run `terraform destroy -refresh=false -auto-approve` to destroy all resources again. 99 | 100 | 101 | 102 | [homepage]: https://mineiros.io/?ref=terraform-aws-s3-bucket 103 | 104 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 105 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform 106 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 107 | [badge-semver]: https://img.shields.io/github/v/tag/mineiros-io/terraform-aws-s3-bucket.svg?label=latest&sort=semver 108 | 109 | [releases-github]: https://github.com/mineiros-io/terraform-aws-s3-bucket/releases 110 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 111 | [apache20]: https://opensource.org/licenses/Apache-2.0 112 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 113 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | [][homepage] 2 | 3 | [![license][badge-license]][apache20] 4 | [![Terraform Version][badge-terraform]][releases-terraform] 5 | [![Join Slack][badge-slack]][slack] 6 | 7 | # Tests 8 | 9 | This directory contains a number of automated tests that cover the functionality 10 | of the modules that ship with this repository. 11 | 12 | ## Introduction 13 | 14 | We are using [Terratest] for automated tests that are located in the 15 | [`test/` directory][Testdirectory]. Terratest deploys _real_ infrastructure 16 | (e.g., servers) in a _real_ environment (e.g., AWS). 17 | 18 | The basic usage pattern for writing automated tests with Terratest is to: 19 | 20 | 1. Write tests using Go's built-in [package testing]: you create a file ending 21 | in `_test.go` and run tests with the `go test` command. 22 | 2. Use Terratest to execute your _real_ IaC tools (e.g., Terraform, Packer, etc.) 23 | to deploy _real_ infrastructure (e.g., servers) in a _real_ environment (e.g., AWS). 24 | 3. Validate that the infrastructure works correctly in that environment by 25 | making HTTP requests, API calls, SSH connections, etc. 26 | 4. Undeploy everything at the end of the test. 27 | 28 | **Note #1**: Many of these tests create real resources in an AWS account. 29 | That means they cost money to run, especially if you don't clean up after 30 | yourself. Please be considerate of the resources you create and take extra care 31 | to clean everything up when you're done! 32 | 33 | **Note #2**: Never hit `CTRL + C` or cancel a build once tests are running or 34 | the cleanup tasks won't run! 35 | 36 | **Note #3**: We set `-timeout 45m` on all tests not because they necessarily 37 | take 45 minutes, but because Go has a default test timeout of 10 minutes, after 38 | which it does a `SIGQUIT`, preventing the tests from properly cleaning up after 39 | themselves. Therefore, we set a timeout of 45 minutes to make sure all tests 40 | have enough time to finish and cleanup. 41 | 42 | ## How to run the tests 43 | 44 | This repository comes with a [Makefile], that helps you to run the 45 | tests in a convenient way. 46 | Alternatively, you can also run the tests without Docker. 47 | 48 | ### Run the tests with Docker 49 | 50 | 1. Install [Docker] 51 | 2. Set your AWS credentials as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` 52 | 3. Run `make test/unit-tests` 53 | 54 | ### Run the tests without Docker 55 | 56 | 1. Install the latest version of [Go]. 57 | 2. Install [Terraform]. 58 | 3. Set your AWS credentials as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` 59 | 4. Install go dependencies: `go mod download` 60 | 5. Run all tests: `go test -v -count 1 -timeout 45m -parallel 128 ./test/...` 61 | or use the convenient `make test/unit-tests` Makefile target. 62 | 6. Run a specific test: `go test -count 1 -v -timeout 45m -parallel 128 test/example_test.go` 63 | 64 | 65 | 66 | [Makefile]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/Makefile 67 | [Testdirectory]: https://github.com/mineiros-io/terraform-aws-s3-bucket/tree/master/test 68 | 69 | [homepage]: https://mineiros.io/?ref=terraform-aws-s3-bucket 70 | [Terratest]: https://github.com/gruntwork-io/terratest 71 | [package testing]: https://golang.org/pkg/testing/ 72 | [Docker]: https://docs.docker.com/get-started/ 73 | [Go]: https://golang.org/ 74 | [Terraform]: https://www.terraform.io/downloads.html 75 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 76 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform 77 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 78 | 79 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 80 | [apache20]: https://opensource.org/licenses/Apache-2.0 81 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 82 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | First and foremost, we'd like to express our gratitude to you for taking the time to contribute. 4 | We welcome and appreciate any and all contributions via 5 | [Pull Requests] along the [GitHub Flow]. 6 | 7 | 1. [Open a GitHub issue](#open-a-github-issue) 8 | 2. [Fork the repository on GitHub](#fork-the-repository-on-github) 9 | 3. [Install the pre-commit hooks](#install-the-pre-commit-hooks) 10 | 4. [Update the documentation](#update-the-documentation) 11 | 5. [Update the tests](#update-the-tests) 12 | 6. [Update the code](#update-the-code) 13 | 7. [Create a pull request](#create-a-pull-request) 14 | 8. [Merge and release](#merge-and-release) 15 | 16 | ## Open a GitHub issue 17 | 18 | For bug reports or requests, please submit your issue in the appropriate repository. 19 | 20 | We advise that you open an issue and ask the 21 | [CODEOWNERS] and community prior to starting a contribution. 22 | This is your chance to ask questions and receive feedback before 23 | writing (potentially wrong) code. We value the direct contact with our community 24 | a lot, so don't hesitate to ask any questions. 25 | 26 | ## Fork the repository on GitHub 27 | 28 | [Fork] the repository into your own GitHub account and [create a new branch] as 29 | described in the [GitHub Flow]. 30 | 31 | ## Install the pre-commit hooks 32 | 33 | If the repository you're working on ships with a 34 | [`.pre-commit-config.yaml`][pre-commit-file], 35 | make sure the necessary hooks have been installed before you begin working 36 | (e.g. a `pre-commit install`). 37 | 38 | ## Update the documentation 39 | 40 | We encourage you to update the documentation before writing any code (please see 41 | [Readme Driven Development]. This ensures the 42 | documentation stays up to date and allows you to think through the problem fully before you begin implementing any 43 | changes. 44 | 45 | ## Update the tests 46 | 47 | We also recommend updating the automated tests before updating any code 48 | (see [Test Driven Development]. 49 | 50 | That means that you should add or update a test case, run all tests and verify 51 | that the new test fails with a clear error message and then start implementing 52 | the code changes to get that test to pass. 53 | 54 | The test folder in every repository will have documentation on how to run the 55 | tests locally. 56 | 57 | ## Update the code 58 | 59 | At this point, make your code changes and constantly test again your new test case to make sure that everything working 60 | properly. Do [commit] early and often and make useful commit messages. 61 | 62 | If a backwards incompatible change cannot be avoided, please make sure to call that out when you submit a pull request, 63 | explaining why the change is absolutely necessary. 64 | 65 | ## Create a pull request 66 | 67 | [Create a pull request] with your changes. 68 | Please make sure to include the following: 69 | 70 | 1. A description of the change, including a link to your GitHub issue. 71 | 1. Any notes on backwards incompatibility or downtime. 72 | 73 | ## Merge and release 74 | 75 | The [CODEOWNERS] of the repository will review your code and provide feedback. 76 | If everything looks good, they will merge the code and release a new version while following the principles of [Semantic Versioning (SemVer)]. 77 | 78 | 79 | 80 | [Pull Requests]: https://github.com/mineiros-io/terraform-aws-s3-bucket/pulls 81 | [pre-commit-file]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/.pre-commit-config.yaml 82 | 83 | [Github Flow]: https://guides.github.com/introduction/flow/ 84 | [CODEOWNERS]: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 85 | [Fork]: https://help.github.com/en/github/getting-started-with-github/fork-a-repo 86 | [create a new branch]: https://guides.github.com/introduction/flow/ 87 | [Readme Driven Development]: https://tom.preston-werner.com/2010/08/23/readme-driven-development.html 88 | [commit]: https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project 89 | [create a pull request]: https://help.github.com/articles/creating-a-pull-request/ 90 | [Semantic Versioning (SemVer)]: https://semver.org/ 91 | [Test Driven Development]: https://en.wikipedia.org/wiki/Test-driven_development 92 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.6.0] 11 | 12 | ### Added 13 | 14 | - Add support for Terraform `v1.x` 15 | 16 | ## [0.5.0] 17 | 18 | ### Added 19 | 20 | - Add support for Terraform `v0.15` 21 | 22 | ## [0.4.2] 23 | 24 | ### Added 25 | 26 | - Add support for Terraform `v0.14.x` 27 | 28 | ## [0.4.1] 29 | 30 | ### Added 31 | 32 | - Prepare support for Terraform `v0.14.x` 33 | 34 | ## [0.4.0] 35 | 36 | ### Added 37 | 38 | - Add support for Terraform `v0.13.x` 39 | - Add support for `module_tags`. 40 | 41 | ## [0.3.0] - 2020-08-03 42 | 43 | ### Changed 44 | 45 | - Add support for Terraform AWS Provider `v3.x` 46 | 47 | ### Removed 48 | 49 | - Remove deprecated `region` argument (BREAKING CHANGE) 50 | 51 | ## [0.2.2] - 2020-07-23 52 | 53 | ### Added 54 | 55 | - Add Changelog.md. 56 | 57 | ### Changed 58 | 59 | - Migrate CI from SemaphoreCI to GitHub Actions. 60 | - Migrate to [golangci-lint](https://github.com/golangci/golangci-lint) instead 61 | of native go tools for pre-commit hooks. 62 | 63 | ## [0.2.1] - 2020-06-13 64 | 65 | ### Added 66 | 67 | - Work around a terraform issue in `module_depends_on` argument. 68 | 69 | ## [0.2.0] - 2020-06-08 70 | 71 | ### Added 72 | 73 | - Implement `module_enabled` and `module_depends_on` this replaces the `create` flag. 74 | - This replaces the backward-incompatible v0.1.5 which we removed right after 75 | noticing the issue. 76 | 77 | ### Changed 78 | 79 | - Upgrade documentation. 80 | 81 | ## [0.1.4] - 2020-04-14 82 | 83 | ### Added 84 | 85 | - Add access point support. 86 | 87 | ### Changed 88 | 89 | - Refactored examples. 90 | 91 | ## [0.1.3] - 2020-03-23 92 | 93 | ### Added 94 | 95 | - Allow log delivery from ELBs in different regions. 96 | 97 | ## [0.1.2] - 2020-03-19 98 | 99 | ### Added 100 | 101 | - Add ELB log delivery option to the module. 102 | 103 | ## [0.1.1] - 2020-03-04 104 | 105 | ### Added 106 | 107 | - Add the option to grant read-only access to existing Cloudfront Origin Access 108 | Identities via `origin_access_identities`. 109 | 110 | ## [0.1.0] - 2020-02-29 111 | 112 | ### Added 113 | 114 | - Add support for Origin Access Identity Access from Cloudfront. 115 | 116 | ## [0.0.3] - 2020-01-24 117 | 118 | ### Changed 119 | 120 | - Update minimum Terraform version to `v0.12.20` so we can take advantage of `try()` and `can()` 121 | - Update README.md with and align it with our new format 122 | 123 | ## [0.0.2] - 2020-01-20 124 | 125 | ### Added 126 | 127 | - SemaphoreCI Integration that will run build, pre-commit checks and unit tests. 128 | - Add an example and a simple test case. 129 | - Further elaboration in README.md. 130 | 131 | ## [0.0.1] - 2020-01-02 132 | 133 | ### Added 134 | 135 | - Bucket public access blocking all set to true by default. 136 | - Server-Side-Encryption (SSE) at rest enabled by default (AES256). 137 | - Bucket ACL defaults to canned private ACL. 138 | - Server-Side-Encryption (SSE) enabled by default 139 | - Added support for Versioning, Bucket Logging, Lifecycle Rules, Request Payer, 140 | Cross-Origin Resource Sharing (CORS), Acceleration Status, Bucket Policy and Tags. 141 | 142 | 143 | 144 | [unreleased]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.6.0...HEAD 145 | [0.6.0]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.5.0...v0.6.0 146 | 147 | 148 | 149 | [0.5.0]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.4.2...v0.5.0 150 | [0.4.2]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.4.1...v0.4.2 151 | [0.4.1]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.4.0...v0.4.1 152 | [0.4.0]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.3.0...v0.4.0 153 | [0.3.0]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.2.2...v0.3.0 154 | [0.2.2]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.2.1...v0.2.2 155 | [0.2.1]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.2.0...v0.2.1 156 | [0.2.0]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.1.4...v0.2.0 157 | [0.1.4]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.1.3...v0.1.4 158 | [0.1.3]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.1.2...v0.1.3 159 | [0.1.2]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.1.1...v0.1.2 160 | [0.1.1]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.1.0...v0.1.1 161 | [0.1.0]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.0.3...v0.1.0 162 | [0.0.3]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.0.2...v0.0.3 163 | [0.0.2]: https://github.com/mineiros-io/terraform-aws-s3-bucket/compare/v0.0.1...v0.0.2 164 | [0.0.1]: https://github.com/mineiros-io/terraform-aws-s3-bucket/releases/tag/v0.0.1 165 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Set default shell to bash 2 | SHELL := /bin/bash -o pipefail 3 | 4 | BUILD_TOOLS_VERSION ?= v0.13.0 5 | BUILD_TOOLS_DOCKER_REPO ?= mineiros/build-tools 6 | BUILD_TOOLS_DOCKER_IMAGE ?= ${BUILD_TOOLS_DOCKER_REPO}:${BUILD_TOOLS_VERSION} 7 | 8 | # Some CI providers such as GitHub Actions, CircleCI, and TravisCI are setting 9 | # the CI environment variable to a non-empty value by default to indicate that 10 | # the current workflow is running in a Continuous Integration environment. 11 | # 12 | # If TF_IN_AUTOMATION is set to any non-empty value, Terraform adjusts its 13 | # output to avoid suggesting specific commands to run next. 14 | # https://www.terraform.io/docs/commands/environment-variables.html#tf_in_automation 15 | # 16 | # We are using GNU style quiet commands to disable set V to non-empty e.g. V=1 17 | # https://www.gnu.org/software/automake/manual/html_node/Debugging-Make-Rules.html 18 | # 19 | ifdef CI 20 | TF_IN_AUTOMATION ?= yes 21 | export TF_IN_AUTOMATION 22 | 23 | V ?= 1 24 | endif 25 | 26 | ifndef NOCOLOR 27 | GREEN := $(shell tput -Txterm setaf 2) 28 | YELLOW := $(shell tput -Txterm setaf 3) 29 | WHITE := $(shell tput -Txterm setaf 7) 30 | RESET := $(shell tput -Txterm sgr0) 31 | endif 32 | 33 | GIT_TOPLEVEl = $(shell git rev-parse --show-toplevel) 34 | 35 | # Generic docker run flags 36 | DOCKER_RUN_FLAGS += -v ${GIT_TOPLEVEl}:/build 37 | DOCKER_RUN_FLAGS += --rm 38 | DOCKER_RUN_FLAGS += -e TF_IN_AUTOMATION 39 | # If TF_VERSION is defined, TFSwitch will switch to the desired version on 40 | # container startup. If TF_VERSION is omitted, the default version installed 41 | # inside the docker image will be used. 42 | DOCKER_RUN_FLAGS += -e TF_VERSION 43 | 44 | # If SSH_AUTH_SOCK is set, we forward the SSH agent of the host system into 45 | # the docker container. This is useful when working with private repositories 46 | # and dependencies that might need to be cloned inside the container (e.g. 47 | # private Terraform modules). 48 | ifdef SSH_AUTH_SOCK 49 | DOCKER_SSH_FLAGS += -e SSH_AUTH_SOCK=/ssh-agent 50 | DOCKER_SSH_FLAGS += -v ${SSH_AUTH_SOCK}:/ssh-agent 51 | endif 52 | 53 | # If AWS_ACCESS_KEY_ID is defined, we are likely running inside an AWS provider 54 | # module. To enable AWS authentication inside the docker container, we inject 55 | # the relevant environment variables. 56 | ifdef AWS_ACCESS_KEY_ID 57 | DOCKER_AWS_FLAGS += -e AWS_ACCESS_KEY_ID 58 | DOCKER_AWS_FLAGS += -e AWS_SECRET_ACCESS_KEY 59 | DOCKER_AWS_FLAGS += -e AWS_SESSION_TOKEN 60 | endif 61 | 62 | # If GITHUB_OWNER is defined, we are likely running inside a GitHub provider 63 | # module. To enable GitHub authentication inside the docker container, 64 | # we inject the relevant environment variables. 65 | ifdef GITHUB_OWNER 66 | DOCKER_GITHUB_FLAGS += -e GITHUB_TOKEN 67 | DOCKER_GITHUB_FLAGS += -e GITHUB_OWNER 68 | endif 69 | 70 | .PHONY: default 71 | default: help 72 | 73 | # Not exposed as a callable target by `make help`, since this is a one-time shot to simplify the development of this module. 74 | .PHONY: template/adjust 75 | template/adjust: FILTER = -path ./.git -prune -a -type f -o -type f -not -name Makefile 76 | template/adjust: 77 | @find . $(FILTER) -exec sed -i -e "s,terraform-module-template,$${PWD##*/},g" {} \; 78 | 79 | ## Run pre-commit hooks inside a build-tools docker container. 80 | .PHONY: test/pre-commit 81 | test/pre-commit: DOCKER_FLAGS += ${DOCKER_SSH_FLAGS} 82 | test/pre-commit: 83 | $(call docker-run,pre-commit run -a) 84 | 85 | ## Run all Go tests inside a build-tools docker container. This is complementary to running 'go test ./test/...'. 86 | .PHONY: test/unit-tests 87 | test/unit-tests: DOCKER_FLAGS += ${DOCKER_SSH_FLAGS} 88 | test/unit-tests: DOCKER_FLAGS += ${DOCKER_GITHUB_FLAGS} 89 | test/unit-tests: DOCKER_FLAGS += ${DOCKER_AWS_FLAGS} 90 | test/unit-tests: DOCKER_FLAGS += -e TF_DATA_DIR=.terratest 91 | test/unit-tests: TEST ?= "TestUnit" 92 | test/unit-tests: 93 | @echo "${YELLOW}[TEST] ${GREEN}Start Running Go Tests in Docker Container.${RESET}" 94 | $(call go-test,./test -run $(TEST)) 95 | 96 | ## Clean up cache and temporary files 97 | .PHONY: clean 98 | clean: 99 | $(call rm-command,.terraform) 100 | $(call rm-command,.terraform.lock.hcl) 101 | $(call rm-command,*.tfplan) 102 | $(call rm-command,*/*/.terraform) 103 | $(call rm-command,*/*/*.tfplan) 104 | $(call rm-command,*/*/.terraform.lock.hcl) 105 | 106 | ## Display help for all targets 107 | .PHONY: help 108 | help: 109 | @awk '/^.PHONY: / { \ 110 | msg = match(lastLine, /^## /); \ 111 | if (msg) { \ 112 | cmd = substr($$0, 9, 100); \ 113 | msg = substr(lastLine, 4, 1000); \ 114 | printf " ${GREEN}%-30s${RESET} %s\n", cmd, msg; \ 115 | } \ 116 | } \ 117 | { lastLine = $$0 }' $(MAKEFILE_LIST) 118 | 119 | ## Generate README.md with Terradoc 120 | .PHONY: terradoc 121 | terradoc: 122 | $(call quiet-command,terradoc -o README.md README.tfdoc.hcl) 123 | 124 | # Define helper functions 125 | DOCKER_FLAGS += ${DOCKER_RUN_FLAGS} 126 | DOCKER_RUN_CMD = docker run ${DOCKER_FLAGS} ${BUILD_TOOLS_DOCKER_IMAGE} 127 | 128 | quiet-command = $(if ${V},${1},$(if ${2},@echo ${2} && ${1}, @${1})) 129 | docker-run = $(call quiet-command,${DOCKER_RUN_CMD} ${1} | cat,"${YELLOW}[DOCKER RUN] ${GREEN}${1}${RESET}") 130 | go-test = $(call quiet-command,${DOCKER_RUN_CMD} go test -v -count 1 -timeout 45m -parallel 128 ${1} | cat,"${YELLOW}[TEST] ${GREEN}${1}${RESET}") 131 | rm-command = $(call quiet-command,rm -rf ${1},"${YELLOW}[CLEAN] ${GREEN}${1}${RESET}") 132 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # REQUIRED PARAMETERS 3 | # These variables must be set when using this module. 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | # --------------------------------------------------------------------------------------------------------------------- 7 | # OPTIONAL PARAMETERS 8 | # These variables have defaults, but may be overridden. 9 | # --------------------------------------------------------------------------------------------------------------------- 10 | 11 | variable "bucket" { 12 | description = "The name of the bucket. (forces new resource, default: unique random name)" 13 | type = string 14 | default = null 15 | } 16 | 17 | variable "bucket_prefix" { 18 | description = "Creates a unique bucket name beginning with the specified prefix. Conflicts with bucket. (forces new resource)" 19 | type = string 20 | default = null 21 | } 22 | 23 | variable "acl" { 24 | description = "The canned ACL to apply. https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl" 25 | type = string 26 | default = "private" 27 | } 28 | 29 | variable "policy" { 30 | description = "A bucket policy in JSON format." 31 | type = string 32 | default = null 33 | } 34 | 35 | variable "tags" { 36 | description = "A mapping of tags to assign to the bucket." 37 | type = map(string) 38 | default = {} 39 | 40 | # Example: 41 | # 42 | # tags = { 43 | # Name = "Just an Example" 44 | # Environment = "Testing" 45 | # } 46 | } 47 | 48 | variable "force_destroy" { 49 | description = "A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable." 50 | type = bool 51 | default = false 52 | } 53 | 54 | variable "acceleration_status" { 55 | description = "Sets the accelerate configuration of an existing bucket. Can be Enabled or Suspended." 56 | type = string 57 | default = null 58 | } 59 | 60 | variable "request_payer" { 61 | description = "Specifies who should bear the cost of Amazon S3 data transfer. Can be either BucketOwner or Requester. See Requester Pays Buckets developer guide for more information." 62 | type = string 63 | default = "BucketOwner" 64 | } 65 | 66 | variable "cors_rule" { 67 | description = "Object containing a rule of Cross-Origin Resource Sharing." 68 | type = any 69 | default = {} 70 | 71 | # Example: 72 | # 73 | # cors_rule = { 74 | # allowed_headers = ["*"] 75 | # allowed_methods = ["PUT", "POST"] 76 | # allowed_origins = ["https://s3-website-test.example.com"] 77 | # expose_headers = ["ETag"] 78 | # max_age_seconds = 3000 79 | # } 80 | } 81 | 82 | variable "versioning" { 83 | description = "Boolean specifying enabled state of versioning or object containing detailed versioning configuration." 84 | type = any 85 | default = false 86 | 87 | # Examples: 88 | # 89 | # versioning = true 90 | # versioning = { 91 | # enabled = true 92 | # mfa_delete = true 93 | # } 94 | } 95 | 96 | variable "logging" { 97 | description = "Map containing access bucket logging configuration." 98 | type = map(string) 99 | default = {} 100 | 101 | # Example: 102 | # 103 | # logging = { 104 | # target_bucket = "example-bucket" 105 | # target_prefix = "log/" 106 | # } 107 | } 108 | 109 | variable "apply_server_side_encryption_by_default" { 110 | description = "Map containing server-side encryption configuration." 111 | type = map(string) 112 | default = { 113 | sse_algorithm = "AES256" 114 | } 115 | } 116 | 117 | variable "lifecycle_rules" { 118 | description = "List of maps containing configuration of object lifecycle management." 119 | type = any 120 | default = [] 121 | 122 | # Example: 123 | # 124 | # lifecycle_rules = [ 125 | # { 126 | # id = "log" 127 | # enabled = true 128 | # 129 | # prefix = "log/" 130 | # 131 | # tags = { 132 | # "rule" = "log" 133 | # "autoclean" = "true" 134 | # } 135 | # 136 | # transition = [ 137 | # { 138 | # days = 30 139 | # storage_class = "STANDARD_IA" # or "ONEZONE_IA" 140 | # }, 141 | # { 142 | # days = 60 143 | # storage_class = "GLACIER" 144 | # } 145 | # ] 146 | # 147 | # expiration = { 148 | # days = 90 149 | # } 150 | # } 151 | # ] 152 | } 153 | 154 | variable "block_public_acls" { 155 | type = bool 156 | description = "Whether Amazon S3 should block public ACLs for this bucket." 157 | default = true 158 | } 159 | 160 | variable "block_public_policy" { 161 | type = bool 162 | description = "Whether Amazon S3 should block public bucket policies for this bucket." 163 | default = true 164 | } 165 | 166 | variable "ignore_public_acls" { 167 | type = bool 168 | description = "Whether Amazon S3 should ignore public ACLs for this bucket." 169 | default = true 170 | } 171 | 172 | variable "restrict_public_buckets" { 173 | type = bool 174 | description = "Whether Amazon S3 should restrict public bucket policies for this bucket." 175 | default = true 176 | } 177 | 178 | variable "cross_account_identifiers" { 179 | type = list(string) 180 | description = "Identifiers that you want to grant cross account access to." 181 | default = [] 182 | 183 | # Example: 184 | # 185 | # cross_account_identifiers = [ 186 | # "112233445566", 187 | # "112233445566" 188 | # ] 189 | } 190 | 191 | variable "cross_account_bucket_actions" { 192 | type = list(string) 193 | description = "Actions on the bucket to allow" 194 | default = [ 195 | "s3:ListBucket" 196 | ] 197 | } 198 | 199 | variable "cross_account_object_actions" { 200 | type = list(string) 201 | description = "Actions on bucket objects to allow" 202 | default = [ 203 | "s3:GetObject" 204 | ] 205 | } 206 | 207 | variable "cross_account_object_actions_with_forced_acl" { 208 | type = list(string) 209 | description = "Actions on bucket objects to allow only with forced acl" 210 | default = [ 211 | "s3:PutObject", 212 | "s3:PutObjectAcl" 213 | ] 214 | } 215 | 216 | variable "cross_account_forced_acls" { 217 | type = list(string) 218 | description = "ACLs to force on new objects for cross account xs" 219 | default = [ 220 | "bucket-owner-full-control" 221 | ] 222 | } 223 | 224 | variable "create_origin_access_identity" { 225 | type = bool 226 | description = "Whether to create an origin access identity (OAI) and policy to be accessible from Cloudfront." 227 | default = false 228 | } 229 | 230 | variable "origin_access_identities" { 231 | type = list(string) 232 | description = "Cloudfront Origin Access Identities to grant read-only access to." 233 | default = [] 234 | } 235 | 236 | variable "elb_log_delivery" { 237 | type = bool 238 | description = "Whether to allow log delivery from ELBs." 239 | default = null 240 | } 241 | 242 | variable "elb_regions" { 243 | type = list(string) 244 | description = "The names of the region whose AWS ELB account IDs are desired." 245 | default = [] 246 | } 247 | 248 | variable "access_points" { 249 | type = any 250 | description = "A List of Access Point configurations." 251 | default = [] 252 | } 253 | 254 | # ------------------------------------------------------------------------------ 255 | # OPTIONAL MODULE CONFIGURATION PARAMETERS 256 | # These variables are used to configure the module. 257 | # See https://medium.com/mineiros/the-ultimate-guide-on-how-to-write-terraform-modules-part-1-81f86d31f024 258 | # ------------------------------------------------------------------------------ 259 | 260 | variable "module_enabled" { 261 | type = bool 262 | description = "(optional) Whether to create resources within the module or not. Default is true." 263 | default = true 264 | } 265 | 266 | variable "module_tags" { 267 | type = map(string) 268 | description = "(Optional) A map of tags that will be applied to all created resources that accept tags. Tags defined with 'module_tags' can be overwritten by resource-specific tags." 269 | default = {} 270 | } 271 | 272 | variable "module_depends_on" { 273 | type = any 274 | description = "(optional) A list of external resources the module depends_on. Default is []." 275 | default = [] 276 | } 277 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2020] [Mineiros GmbH] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # CREATE A S3 BUCKET THAT IS SECURED BY DEFAULT 3 | # - Bucket public access blocking all set to true 4 | # - Server-Side-Encryption (SSE) at rest enabled by default (AES256), 5 | # --------------------------------------------------------------------------------------------------------------------- 6 | 7 | # --------------------------------------------------------------------------------------------------------------------- 8 | # Set default values for the S3 Bucket 9 | # --------------------------------------------------------------------------------------------------------------------- 10 | 11 | locals { 12 | cors_enabled = length(keys(var.cors_rule)) > 0 13 | logging_enabled = length(keys(var.logging)) > 0 14 | sse_enabled = length(keys(var.apply_server_side_encryption_by_default)) > 0 15 | 16 | cors = local.cors_enabled ? [var.cors_rule] : [] 17 | logging = local.logging_enabled ? [var.logging] : [] 18 | encryption = local.sse_enabled ? [var.apply_server_side_encryption_by_default] : [] 19 | 20 | versioning = try( 21 | [{ enabled = tobool(var.versioning) }], 22 | length(keys(var.versioning)) > 0 ? [var.versioning] : [], 23 | [] 24 | ) 25 | } 26 | 27 | # --------------------------------------------------------------------------------------------------------------------- 28 | # Create the S3 Bucket 29 | # --------------------------------------------------------------------------------------------------------------------- 30 | 31 | locals { 32 | tags = merge(var.module_tags, var.tags) 33 | bucket_tags = length(local.tags) > 0 ? local.tags : null 34 | } 35 | 36 | resource "aws_s3_bucket" "bucket" { 37 | count = var.module_enabled ? 1 : 0 38 | 39 | bucket = var.bucket 40 | bucket_prefix = var.bucket_prefix 41 | acl = var.acl 42 | tags = local.bucket_tags 43 | force_destroy = var.force_destroy 44 | acceleration_status = var.acceleration_status 45 | request_payer = var.request_payer 46 | 47 | dynamic "cors_rule" { 48 | for_each = local.cors 49 | 50 | content { 51 | allowed_headers = lookup(cors_rule.value, "allowed_headers", null) 52 | allowed_methods = cors_rule.value.allowed_methods 53 | allowed_origins = cors_rule.value.allowed_origins 54 | expose_headers = lookup(cors_rule.value, "expose_headers", null) 55 | max_age_seconds = lookup(cors_rule.value, "max_age_seconds", null) 56 | } 57 | } 58 | 59 | dynamic "versioning" { 60 | for_each = local.versioning 61 | 62 | content { 63 | enabled = lookup(versioning.value, "enabled", null) 64 | mfa_delete = lookup(versioning.value, "mfa_delete", false) 65 | } 66 | } 67 | 68 | dynamic "logging" { 69 | for_each = local.logging 70 | 71 | content { 72 | target_bucket = logging.value.target_bucket 73 | target_prefix = lookup(logging.value, "target_prefix", null) 74 | } 75 | } 76 | 77 | dynamic "server_side_encryption_configuration" { 78 | for_each = local.encryption 79 | iterator = sse 80 | 81 | content { 82 | rule { 83 | apply_server_side_encryption_by_default { 84 | kms_master_key_id = lookup(sse.value, "kms_master_key_id", null) 85 | sse_algorithm = lookup(sse.value, "sse_algorithm", 86 | lookup(sse.value, "kms_master_key_id", null) == null ? "AES256" : "aws:kms" 87 | ) 88 | } 89 | } 90 | } 91 | } 92 | 93 | dynamic "lifecycle_rule" { 94 | for_each = var.lifecycle_rules 95 | iterator = rule 96 | 97 | content { 98 | id = lookup(rule.value, "id", null) 99 | prefix = lookup(rule.value, "prefix", null) 100 | tags = lookup(rule.value, "tags", null) 101 | abort_incomplete_multipart_upload_days = lookup(rule.value, "abort_incomplete_multipart_upload_days", null) 102 | enabled = rule.value.enabled 103 | 104 | dynamic "expiration" { 105 | for_each = length(keys(lookup(rule.value, "expiration", {}))) == 0 ? [] : [rule.value.expiration] 106 | 107 | content { 108 | date = lookup(expiration.value, "date", null) 109 | days = lookup(expiration.value, "days", null) 110 | expired_object_delete_marker = lookup(expiration.value, "expired_object_delete_marker", null) 111 | } 112 | } 113 | 114 | dynamic "transition" { 115 | for_each = lookup(rule.value, "transition", []) 116 | 117 | content { 118 | date = lookup(transition.value, "date", null) 119 | days = lookup(transition.value, "days", null) 120 | storage_class = transition.value.storage_class 121 | } 122 | } 123 | 124 | dynamic "noncurrent_version_expiration" { 125 | for_each = length(keys(lookup(rule.value, "noncurrent_version_expiration", {}))) == 0 ? [] : [rule.value.noncurrent_version_expiration] 126 | iterator = expiration 127 | 128 | content { 129 | days = lookup(expiration.value, "days", null) 130 | } 131 | } 132 | 133 | dynamic "noncurrent_version_transition" { 134 | for_each = lookup(rule.value, "noncurrent_version_transition", []) 135 | iterator = transition 136 | 137 | content { 138 | days = lookup(transition.value, "days", null) 139 | storage_class = transition.value.storage_class 140 | } 141 | } 142 | } 143 | } 144 | 145 | depends_on = [var.module_depends_on] 146 | } 147 | 148 | # --------------------------------------------------------------------------------------------------------------------- 149 | # Set default values for the S3 Bucket Policy 150 | # --------------------------------------------------------------------------------------------------------------------- 151 | 152 | locals { 153 | bucket_id = join("", aws_s3_bucket.bucket.*.id) 154 | bucket_arn = join("", aws_s3_bucket.bucket.*.arn) 155 | 156 | cross_account_enabled = length(var.cross_account_identifiers) > 0 157 | 158 | cross_account_bucket_actions_enabled = local.cross_account_enabled && length(var.cross_account_bucket_actions) > 0 159 | cross_account_object_actions_enabled = local.cross_account_enabled && length(var.cross_account_object_actions) > 0 160 | cross_account_object_actions_with_forced_acl_enabled = local.cross_account_enabled && length(var.cross_account_object_actions_with_forced_acl) > 0 161 | 162 | cross_account_actions_enabled = local.cross_account_bucket_actions_enabled || local.cross_account_object_actions_enabled || local.cross_account_object_actions_with_forced_acl_enabled 163 | 164 | origin_access_identities_enabled = var.module_enabled && (var.create_origin_access_identity || length(var.origin_access_identities) > 0) 165 | 166 | elb_log_delivery = var.elb_log_delivery != null ? var.elb_log_delivery : var.acl == "log-delivery-write" || length(var.elb_regions) > 0 167 | 168 | policy_enabled = var.module_enabled && (var.policy != null || local.cross_account_actions_enabled || local.origin_access_identities_enabled || local.elb_log_delivery) 169 | } 170 | 171 | # --------------------------------------------------------------------------------------------------------------------- 172 | # Create the S3 Bucket Public Access Block Policy 173 | # All public access should be blocked per default 174 | # --------------------------------------------------------------------------------------------------------------------- 175 | 176 | resource "aws_s3_bucket_public_access_block" "bucket" { 177 | count = var.module_enabled ? 1 : 0 178 | 179 | bucket = local.bucket_id 180 | 181 | block_public_acls = var.block_public_acls 182 | block_public_policy = var.block_public_policy 183 | ignore_public_acls = var.ignore_public_acls 184 | restrict_public_buckets = var.restrict_public_buckets 185 | 186 | depends_on = [var.module_depends_on] 187 | } 188 | 189 | # --------------------------------------------------------------------------------------------------------------------- 190 | # Attach a Policy to the S3 Bucket to control: 191 | # - Cross account bucket actions 192 | # - Cross account object actions 193 | # - Cloudfront origin access identity access 194 | # --------------------------------------------------------------------------------------------------------------------- 195 | 196 | resource "aws_s3_bucket_policy" "bucket" { 197 | count = local.policy_enabled ? 1 : 0 198 | 199 | bucket = local.bucket_id 200 | 201 | # remove whitespaces by decoding and encoding again to suppress terrform output whitespace cahnges 202 | policy = try(jsonencode(jsondecode(data.aws_iam_policy_document.bucket[0].json)), null) 203 | 204 | depends_on = [ 205 | var.module_depends_on, 206 | aws_s3_bucket_public_access_block.bucket, 207 | ] 208 | } 209 | 210 | data "aws_iam_policy_document" "bucket" { 211 | count = local.policy_enabled ? 1 : 0 212 | 213 | source_json = var.policy 214 | 215 | dynamic "statement" { 216 | for_each = local.cross_account_bucket_actions_enabled ? [1] : [] 217 | 218 | content { 219 | actions = var.cross_account_bucket_actions 220 | resources = [local.bucket_arn] 221 | 222 | principals { 223 | type = "AWS" 224 | identifiers = var.cross_account_identifiers 225 | } 226 | } 227 | } 228 | 229 | dynamic "statement" { 230 | for_each = local.cross_account_object_actions_enabled ? [1] : [] 231 | 232 | content { 233 | actions = var.cross_account_object_actions 234 | resources = ["${local.bucket_arn}/*"] 235 | 236 | principals { 237 | type = "AWS" 238 | identifiers = var.cross_account_identifiers 239 | } 240 | } 241 | } 242 | 243 | dynamic "statement" { 244 | for_each = local.cross_account_object_actions_with_forced_acl_enabled ? [1] : [] 245 | 246 | content { 247 | actions = var.cross_account_object_actions_with_forced_acl 248 | resources = ["${local.bucket_arn}/*"] 249 | 250 | principals { 251 | type = "AWS" 252 | identifiers = var.cross_account_identifiers 253 | } 254 | 255 | dynamic "condition" { 256 | for_each = length(var.cross_account_forced_acls) == 0 ? [] : [1] 257 | 258 | content { 259 | test = "StringEquals" 260 | variable = "s3:x-amz-acl" 261 | values = var.cross_account_forced_acls 262 | } 263 | } 264 | } 265 | } 266 | 267 | dynamic "statement" { 268 | for_each = local.origin_access_identities_enabled ? [{ 269 | actions = ["s3:GetObject"] 270 | resources = ["${local.bucket_arn}/*"] 271 | }, { 272 | actions = ["s3:ListBucket"] 273 | resources = [local.bucket_arn] 274 | 275 | }] : [] 276 | content { 277 | actions = statement.value.actions 278 | resources = statement.value.resources 279 | 280 | principals { 281 | type = "AWS" 282 | identifiers = local.oai_identities 283 | } 284 | } 285 | } 286 | 287 | dynamic "statement" { 288 | for_each = local.elb_log_delivery ? [1] : [] 289 | 290 | content { 291 | actions = ["s3:PutObject"] 292 | resources = ["${local.bucket_arn}/*"] 293 | 294 | principals { 295 | type = "AWS" 296 | identifiers = sort(local.elb_accounts) 297 | } 298 | } 299 | } 300 | } 301 | 302 | locals { 303 | oai_identities = concat( 304 | var.origin_access_identities, 305 | aws_cloudfront_origin_access_identity.oai.*.iam_arn 306 | ) 307 | } 308 | 309 | resource "aws_cloudfront_origin_access_identity" "oai" { 310 | count = var.module_enabled && var.create_origin_access_identity ? 1 : 0 311 | 312 | comment = format("%s S3 buckets Origin Access Identity to be accessed from CloudFront", local.bucket_id) 313 | 314 | depends_on = [var.module_depends_on] 315 | } 316 | 317 | locals { 318 | elb_accounts = length(var.elb_regions) > 0 ? data.aws_elb_service_account.elbs.*.arn : [data.aws_elb_service_account.elb.arn] 319 | } 320 | 321 | data "aws_elb_service_account" "elb" {} 322 | 323 | data "aws_elb_service_account" "elbs" { 324 | count = length(var.elb_regions) 325 | 326 | region = var.elb_regions[count.index] 327 | } 328 | 329 | # --------------------------------------------------------------------------------------------------------------------- 330 | # Create S3 Access Points 331 | # --------------------------------------------------------------------------------------------------------------------- 332 | locals { 333 | aps = { for idx, ap in var.access_points : ap.name => idx } 334 | } 335 | 336 | resource "aws_s3_access_point" "ap" { 337 | for_each = var.module_enabled ? local.aps : {} 338 | 339 | bucket = local.bucket_id 340 | name = var.access_points[each.value].name 341 | 342 | # optional values 343 | account_id = try(var.access_points[each.value].account_id, null) 344 | policy = try(var.access_points[each.value].policy, null) 345 | 346 | # optional but block all public access by default 347 | public_access_block_configuration { 348 | block_public_acls = try(var.access_points[each.value].block_public_acls, true) 349 | block_public_policy = try(var.access_points[each.value].block_public_policy, true) 350 | ignore_public_acls = try(var.access_points[each.value].ignore_public_acls, true) 351 | restrict_public_buckets = try(var.access_points[each.value].restrict_public_buckets, true) 352 | } 353 | 354 | dynamic "vpc_configuration" { 355 | for_each = try([var.access_points[each.value].vpc_id], []) 356 | 357 | content { 358 | vpc_id = vpc_configuration.each.value 359 | } 360 | } 361 | 362 | depends_on = [var.module_depends_on] 363 | } 364 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://mineiros.io/?ref=terraform-aws-s3-bucket) 2 | 3 | [![Build Status](https://github.com/mineiros-io/terraform-aws-s3-bucket/workflows/CI/CD%20Pipeline/badge.svg)](https://github.com/mineiros-io/terraform-aws-s3-bucket/actions) 4 | [![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/mineiros-io/terraform-aws-s3-bucket.svg?label=latest&sort=semver)](https://github.com/mineiros-io/terraform-aws-s3-bucket/releases) 5 | [![Terraform Version](https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform)](https://github.com/hashicorp/terraform/releases) 6 | [![AWS Provider Version](https://img.shields.io/badge/AWS-3%20and%202.0+-F8991D.svg?logo=terraform)](https://github.com/terraform-providers/terraform-provider-aws/releases) 7 | [![Join Slack](https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack)](https://mineiros.io/slack) 8 | 9 | # terraform-aws-s3-bucket 10 | 11 | A [Terraform] base module for creating a secure [AWS S3-Bucket]. 12 | 13 | ***This module supports Terraform v1.x, v0.15, v0.14, v0.13 as well as v0.12.20 and above 14 | and is compatible with the terraform AWS provider v3 as well as v2.0 and above.*** 15 | 16 | 17 | - [Module Features](#module-features) 18 | - [Getting Started](#getting-started) 19 | - [Module Argument Reference](#module-argument-reference) 20 | - [Bucket Configuration](#bucket-configuration) 21 | - [Extended Resource Configuration](#extended-resource-configuration) 22 | - [S3 Access Points](#s3-access-points) 23 | - [S3 bucket-level Public Access Block Configuration](#s3-bucket-level-public-access-block-configuration) 24 | - [Cross Account Access Configuration](#cross-account-access-configuration) 25 | - [Cloudfront Origin Access Identity Access](#cloudfront-origin-access-identity-access) 26 | - [ELB Log Delivery](#elb-log-delivery) 27 | - [Module Configuration](#module-configuration) 28 | - [Module Outputs](#module-outputs) 29 | - [External Documentation](#external-documentation) 30 | - [AWS Documentation S3](#aws-documentation-s3) 31 | - [Terraform AWS Provider Documentation](#terraform-aws-provider-documentation) 32 | - [Module Versioning](#module-versioning) 33 | - [Backwards compatibility in `0.0.z` and `0.y.z` version](#backwards-compatibility-in-00z-and-0yz-version) 34 | - [About Mineiros](#about-mineiros) 35 | - [Reporting Issues](#reporting-issues) 36 | - [Contributing](#contributing) 37 | - [Makefile Targets](#makefile-targets) 38 | - [License](#license) 39 | 40 | ## Module Features 41 | 42 | In contrast to the plain `aws_s3_bucket` resource this module creates secure 43 | buckets by default. While all security features can be disabled as needed, best practices 44 | are pre-configured. 45 | 46 | In addition to security, easy cross-account access can be granted to the objects 47 | of the bucket enforcing `bucket-owner-full-control` ACL for objects created by other accounts. 48 | 49 | - **Default Security Settings**: 50 | Bucket public access blocking all set to `true` by default, 51 | Server-Side-Encryption (SSE) at rest `enabled` by default (AES256), 52 | Bucket ACL defaults to canned `private` ACL 53 | 54 | - **Standard S3 Features**: 55 | Server-Side-Encryption (SSE) enabled by default, 56 | Versioning, 57 | Bucket Logging, 58 | Lifecycle Rules, 59 | Request Payer, 60 | Cross-Origin Resource Sharing (CORS), 61 | Acceleration Status, 62 | Bucket Policy, 63 | Tags 64 | 65 | - **Extended S3 Features**: 66 | Bucket Public Access Blocking, 67 | S3 Access Points 68 | 69 | - **Additional Features**: 70 | Cross-Account access policy with forced `bucket-owner-full-control` ACL for direct access, 71 | Create Cloudfront Origin Access Identity (OAI) and grant read-only access, 72 | Grant read-only access to existing Cloudfront Origin Access Identity (OAI), 73 | Allow ELB log delivery 74 | 75 | - *Features not yet implemented*: 76 | Enforce Encryption via a policy that blocks unencrypted uploads, 77 | ACL policy grants (aws-provider >= 2.52.0), 78 | Amazon S3 Analytics (aws-provider >= 2.49.0), 79 | Replication Configuration, 80 | Website Configuration, 81 | S3 Object Locking, 82 | Bucket Notifications, 83 | Bucket Metrics, 84 | Bucket Inventory, 85 | Generate Cross-Account role for OAI enabled buckets if desired, 86 | Generate KMS key to encrypt objects at rest if desired 87 | 88 | ## Getting Started 89 | 90 | Most basic usage creating a random named secure AWS bucket. 91 | 92 | ```hcl 93 | module "bucket" { 94 | source = "mineiros-io/s3-bucket/aws" 95 | version = "~> 0.6.0" 96 | } 97 | ``` 98 | 99 | Advanced usage as found in [examples/secure-s3-bucket/main.tf] setting all required and optional arguments to their default values. 100 | 101 | ## Module Argument Reference 102 | 103 | See [variables.tf] and [examples/] for details and use-cases. 104 | 105 | ### Bucket Configuration 106 | 107 | - [**`bucket`**](#var-bucket): *(Optional `string`)* 108 | 109 | The name of the bucket. If omitted, Terraform will assign a random, unique name. Forces new resource. 110 | 111 | - [**`bucket_prefix`**](#var-bucket_prefix): *(Optional `string`)* 112 | 113 | Creates a unique bucket name beginning with the specified prefix. Conflicts with `bucket`. Forces new resource. 114 | 115 | - [**`acl`**](#var-acl): *(Optional `string`)* 116 | 117 | The canned ACL to apply. 118 | 119 | Default is `"private"`. 120 | 121 | - [**`policy`**](#var-policy): *(Optional `string`)* 122 | 123 | A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide]. 124 | 125 | Default is `null`. 126 | 127 | - [**`tags`**](#var-tags): *(Optional `map(string)`)* 128 | 129 | A mapping of tags to assign to the bucket. 130 | 131 | Default is `{}`. 132 | 133 | - [**`force_destroy`**](#var-force_destroy): *(Optional `bool`)* 134 | 135 | A boolean that indicates all objects (including any locked objects) should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable. 136 | 137 | Default is `false`. 138 | 139 | - [**`acceleration_status`**](#var-acceleration_status): *(Optional `string`)* 140 | 141 | Sets the accelerate configuration of an existing bucket. Can be `Enabled` or `Suspended`. 142 | 143 | - [**`request_payer`**](#var-request_payer): *(Optional `string`)* 144 | 145 | Specifies who should bear the cost of Amazon S3 data transfer. Can be either `BucketOwner` or `Requester`. 146 | By default, the owner of the S3 bucket would incur the costs of any data transfer. 147 | See [Requester Pays Buckets developer guide] for more information. 148 | 149 | Default is `"BucketOwner"`. 150 | 151 | - [**`cors_rule`**](#var-cors_rule): *(Optional `object(cors)`)* 152 | 153 | Specifying settings for Cross-Origin Resource Sharing (CORS) (documented below). 154 | 155 | Default is `{}`. 156 | 157 | The `cors` object accepts the following attributes: 158 | 159 | - [**`allowed_headers`**](#attr-cors_rule-allowed_headers): *(Optional `list(string)`)* 160 | 161 | Specifies which headers are allowed. 162 | 163 | Default is `[]`. 164 | 165 | - [**`allowed_methods`**](#attr-cors_rule-allowed_methods): *(**Required** `list(string)`)* 166 | 167 | Specifies which methods are allowed. Can be `GET`, `PUT`, `POST`, `DELETE` or `HEAD`. 168 | 169 | - [**`allowed_origins`**](#attr-cors_rule-allowed_origins): *(**Required** `list(string)`)* 170 | 171 | Specifies which origins are allowed. 172 | 173 | - [**`expose_headers`**](#attr-cors_rule-expose_headers): *(Optional `list(string)`)* 174 | 175 | Specifies expose header in the response. 176 | 177 | Default is `[]`. 178 | 179 | - [**`max_age_seconds`**](#attr-cors_rule-max_age_seconds): *(Optional `number`)* 180 | 181 | Specifies time in seconds that browser can cache the response for a preflight request. 182 | 183 | - [**`versioning`**](#var-versioning): *(Optional `bool`)* 184 | 185 | Can also be of type `object`. When set to `true` versioning will be enabled. Specifies Versioning Configuration when passed as an object (documented below). 186 | 187 | Default is `false`. 188 | 189 | The object accepts the following attributes: 190 | 191 | - [**`enabled`**](#attr-versioning-enabled): *(Optional `bool`)* 192 | 193 | Once you version-enable a bucket, it can never return to an unversioned state. 194 | You can, however, suspend versioning on that bucket. 195 | 196 | - [**`mfa_delete`**](#attr-versioning-mfa_delete): *(Optional `bool`)* 197 | 198 | Enable MFA delete for either change: the versioning state of your bucket or 199 | permanently delete an object version. 200 | 201 | Default is `false`. 202 | 203 | - [**`logging`**](#var-logging): *(Optional `map(string)`)* 204 | 205 | Specifying a configuration for logging access logs (documented below). 206 | 207 | Default is `{}`. 208 | 209 | Each `` object in the map accepts the following attributes: 210 | 211 | - [**`target_bucket`**](#attr-logging-target_bucket): *(**Required** `string`)* 212 | 213 | The name of the bucket that will receive the log objects. 214 | 215 | - [**`target_prefix`**](#attr-logging-target_prefix): *(Optional `string`)* 216 | 217 | To specify a key prefix for log objects. 218 | 219 | - [**`apply_server_side_encryption_by_default`**](#var-apply_server_side_encryption_by_default): *(Optional `map(string)`)* 220 | 221 | Specifying the server side encryption to apply to objects at rest (documented below). 222 | Default is to use `AES256` encryption. 223 | 224 | Each `` object in the map accepts the following attributes: 225 | 226 | - [**`sse_algorithm`**](#attr-apply_server_side_encryption_by_default-sse_algorithm): *(Optional `string`)* 227 | 228 | The server-side encryption algorithm to use. Valid values are `AES256` and `aws:kms`. Default applies when `kms_master_key_id` is specified, else `AES256` 229 | 230 | Default is `"aws:kms"`. 231 | 232 | - [**`kms_master_key_id`**](#attr-apply_server_side_encryption_by_default-kms_master_key_id): *(Optional `string`)* 233 | 234 | The AWS KMS master key ID used for the SSE-KMS encryption. The default `aws/s3` AWS KMS master key is used if this element is absent while the sse_algorithm is `aws:kms`. 235 | 236 | Default is `"null"`. 237 | 238 | - [**`lifecycle_rules`**](#var-lifecycle_rules): *(Optional `list(lifecycle_rule)`)* 239 | 240 | Specifying various rules specifying object lifecycle management (documented below). 241 | 242 | Default is `[]`. 243 | 244 | Each `lifecycle_rule` object in the list accepts the following attributes: 245 | 246 | - [**`id`**](#attr-lifecycle_rules-id): *(Optional `string`)* 247 | 248 | Unique identifier for the rule. 249 | 250 | - [**`prefix`**](#attr-lifecycle_rules-prefix): *(Optional `string`)* 251 | 252 | Object key prefix identifying one or more objects to which the rule applies. 253 | 254 | - [**`tags`**](#attr-lifecycle_rules-tags): *(Optional `map(string)`)* 255 | 256 | Specifies object tags key and value. 257 | 258 | - [**`enabled`**](#attr-lifecycle_rules-enabled): *(**Required** `bool`)* 259 | 260 | Specifies lifecycle rule status. 261 | 262 | - [**`abort_incomplete_multipart_upload_days`**](#attr-lifecycle_rules-abort_incomplete_multipart_upload_days): *(Optional `number`)* 263 | 264 | Specifies the number of days after initiating a multipart upload when the multipart upload must be completed. 265 | 266 | - [**`expiration`**](#attr-lifecycle_rules-expiration): *(Optional `object(expiration)`)* 267 | 268 | Specifies a period in the object's expire (documented below). 269 | 270 | The `expiration` object accepts the following attributes: 271 | 272 | - [**`date`**](#attr-lifecycle_rules-expiration-date): *(Optional `string`)* 273 | 274 | Specifies the date after which you want the corresponding action to take effect. 275 | 276 | - [**`days`**](#attr-lifecycle_rules-expiration-days): *(Optional `string`)* 277 | 278 | Specifies the number of days after object creation when the specific rule action takes effect. 279 | 280 | - [**`expired_object_delete_marker`**](#attr-lifecycle_rules-expiration-expired_object_delete_marker): *(Optional `bool`)* 281 | 282 | On a versioned bucket (versioning-enabled or versioning-suspended bucket), you can add this element in the lifecycle configuration to direct Amazon S3 to delete expired object delete markers. 283 | 284 | - [**`transition`**](#attr-lifecycle_rules-transition): *(Optional `object(transition)`)* 285 | 286 | Specifies a period in the object's transitions (documented below). 287 | 288 | The `transition` object accepts the following attributes: 289 | 290 | - [**`date`**](#attr-lifecycle_rules-transition-date): *(Optional `string`)* 291 | 292 | Specifies the date after which you want the corresponding action to take effect. 293 | 294 | - [**`days`**](#attr-lifecycle_rules-transition-days): *(Optional `number`)* 295 | 296 | Specifies the number of days after object creation when the specific rule action takes effect. 297 | 298 | - [**`storage_class`**](#attr-lifecycle_rules-transition-storage_class): *(**Required** `string`)* 299 | 300 | Specifies the Amazon S3 storage class to which you want the object to transition. 301 | Can be `ONEZONE_IA`, `STANDARD_IA`, `INTELLIGENT_TIERING`, `GLACIER`, or `DEEP_ARCHIVE`. 302 | 303 | - [**`noncurrent_version_expiration`**](#attr-lifecycle_rules-noncurrent_version_expiration): *(Optional `object(noncurrent_version_expiration)`)* 304 | 305 | Specifies when noncurrent object versions expire (documented below). 306 | 307 | The `noncurrent_version_expiration` object accepts the following attributes: 308 | 309 | - [**`days`**](#attr-lifecycle_rules-noncurrent_version_expiration-days): *(**Required** `number`)* 310 | 311 | Specifies the number of days an object's noncurrent object versions expire. 312 | 313 | - [**`noncurrent_version_transition`**](#attr-lifecycle_rules-noncurrent_version_transition): *(Optional `object(noncurrent_version_transition)`)* 314 | 315 | Specifies when noncurrent object versions transitions (documented below). 316 | At least one of `expiration`, `transition`, `noncurrent_version_expiration`, `noncurrent_version_transition` must be specified. 317 | 318 | The `noncurrent_version_transition` object accepts the following attributes: 319 | 320 | - [**`days`**](#attr-lifecycle_rules-noncurrent_version_transition-days): *(**Required** `number`)* 321 | 322 | Specifies the number of days an object's noncurrent object versions expire. 323 | 324 | - [**`storage_class`**](#attr-lifecycle_rules-noncurrent_version_transition-storage_class): *(**Required** `string`)* 325 | 326 | Specifies the Amazon S3 storage class to which you want the noncurrent versions object to transition. 327 | Can be `ONEZONE_IA`, `STANDARD_IA`, `INTELLIGENT_TIERING`, `GLACIER`, or `DEEP_ARCHIVE`. 328 | 329 | ### Extended Resource Configuration 330 | 331 | #### S3 Access Points 332 | 333 | - [**`access_points`**](#var-access_points): *(Optional `list(access_point)`)* 334 | 335 | Amazon S3 Access Points simplify managing data access at scale for shared datasets in S3. 336 | Access points are named network endpoints that are attached to buckets that 337 | you can use to perform S3 object operations, such as `GetObject` and `PutObject`. 338 | Each access point has distinct permissions and network controls that S3 applies 339 | for any request that is made through that access point. 340 | Each access point enforces a customized access point policy that works in 341 | conjunction with the bucket policy that is attached to the underlying bucket. 342 | You can configure any access point to accept requests only from a 343 | virtual private cloud (VPC) to restrict Amazon S3 data access to a private network. 344 | You can also configure custom block public access settings for each access point. 345 | 346 | Default is `[]`. 347 | 348 | Each `access_point` object in the list accepts the following attributes: 349 | 350 | - [**`name`**](#attr-access_points-name): *(**Required** `string`)* 351 | 352 | The name you want to assign to this access point. 353 | 354 | - [**`account_id`**](#attr-access_points-account_id): *(Optional `string`)* 355 | 356 | The AWS account ID for the owner of the bucket for which you want to create an access point. 357 | Defaults to automatically determined account ID of the Terraform AWS provider. 358 | 359 | - [**`policy`**](#attr-access_points-policy): *(Optional `string`)* 360 | 361 | A valid JSON document that specifies the policy that you want to apply to this access point. 362 | 363 | - [**`vpc_id`**](#attr-access_points-vpc_id): *(Optional `string`)* 364 | 365 | If set, this access point will only allow connections from the specified VPC ID. 366 | 367 | - [**`block_public_acls`**](#attr-access_points-block_public_acls): *(Optional `bool`)* 368 | 369 | Whether Amazon S3 should block public ACLs for this bucket. 370 | Enabling this setting does not affect existing policies or ACLs. 371 | 372 | Default is `true`. 373 | 374 | - [**`block_public_policy`**](#attr-access_points-block_public_policy): *(Optional `bool`)* 375 | 376 | Whether Amazon S3 should block public bucket policies for this bucket. 377 | Enabling this setting does not affect the existing bucket policy. 378 | If `true`: 379 | - Reject calls to `PUT Bucket policy` if the specified bucket policy allows public access. 380 | 381 | Default is `true`. 382 | 383 | - [**`ignore_public_acls`**](#attr-access_points-ignore_public_acls): *(Optional `bool`)* 384 | 385 | Whether Amazon S3 should ignore public ACLs for this bucket. 386 | Enabling this setting does not affect the persistence of any existing ACLs and 387 | doesn't prevent new public ACLs from being set. 388 | If `true`: 389 | - Ignore public ACLs on this bucket and any objects that it contains. 390 | 391 | Default is `true`. 392 | 393 | - [**`restrict_public_buckets`**](#attr-access_points-restrict_public_buckets): *(Optional `bool`)* 394 | 395 | Whether Amazon S3 should restrict public bucket policies for this bucket. 396 | Enabling this setting does not affect the previously stored bucket policy, 397 | except that public and cross-account access within the public bucket policy, 398 | including non-public delegation to specific accounts, is blocked. 399 | If `true`: 400 | - Only the bucket owner and AWS Services can access this buckets if it has a public policy. 401 | 402 | Default is `true`. 403 | 404 | #### S3 bucket-level Public Access Block Configuration 405 | 406 | - [**`block_public_acls`**](#var-block_public_acls): *(Optional `bool`)* 407 | 408 | Whether Amazon S3 should block public ACLs for this bucket. 409 | Enabling this setting does not affect existing policies or ACLs. 410 | If `true`: 411 | - `PUT Bucket acl` and `PUT Object acl` calls will fail if the specified ACL allows public access. 412 | - `PUT Object` calls will fail if the request includes an object ACL. 413 | 414 | Default is `true`. 415 | 416 | - [**`block_public_policy`**](#var-block_public_policy): *(Optional `bool`)* 417 | 418 | Whether Amazon S3 should block public bucket policies for this bucket. 419 | Enabling this setting does not affect the existing bucket policy. 420 | If `true`: 421 | - Reject calls to `PUT Bucket policy` if the specified bucket policy allows public access. 422 | 423 | Default is `true`. 424 | 425 | - [**`ignore_public_acls`**](#var-ignore_public_acls): *(Optional `bool`)* 426 | 427 | Whether Amazon S3 should ignore public ACLs for this bucket. 428 | Enabling this setting does not affect the persistence of any existing ACLs and 429 | doesn't prevent new public ACLs from being set. 430 | If `true`: 431 | - Ignore public ACLs on this bucket and any objects that it contains. 432 | 433 | Default is `true`. 434 | 435 | - [**`restrict_public_buckets`**](#var-restrict_public_buckets): *(Optional `bool`)* 436 | 437 | Whether Amazon S3 should restrict public bucket policies for this bucket. 438 | Enabling this setting does not affect the previously stored bucket policy, 439 | except that public and cross-account access within the public bucket policy, 440 | including non-public delegation to specific accounts, is blocked. 441 | If `true`: 442 | - Only the bucket owner and AWS Services can access this buckets if it has a public policy. 443 | 444 | Default is `true`. 445 | 446 | #### Cross Account Access Configuration 447 | 448 | - [**`cross_account_identifiers`**](#var-cross_account_identifiers): *(Optional `list(string)`)* 449 | 450 | Specifies identifiers that should be granted cross account access to. 451 | If this list is empty Cross Account Access is not configured and all other 452 | options in this category are ignored. 453 | 454 | Default is `[]`. 455 | 456 | - [**`cross_account_bucket_actions`**](#var-cross_account_bucket_actions): *(Optional `list(string)`)* 457 | 458 | Specifies actions on the bucket to grant from cross account. 459 | 460 | Default is `["s3:ListBucket"]`. 461 | 462 | - [**`cross_account_object_actions`**](#var-cross_account_object_actions): *(Optional `list(string)`)* 463 | 464 | Specifies actions on bucket objects to grant from cross account. 465 | 466 | Default is `["s3:GetObject"]`. 467 | 468 | - [**`cross_account_object_actions_with_forced_acl`**](#var-cross_account_object_actions_with_forced_acl): *(Optional `list(string)`)* 469 | 470 | Specifies actions on bucket objects to grant only with foreced ACL from cross account. 471 | 472 | Default is `["s3:PutObject","s3:PutObjectAcl"]`. 473 | 474 | - [**`cross_account_forced_acls`**](#var-cross_account_forced_acls): *(Optional `list(string)`)* 475 | 476 | Specifies ACLs to force on new objects for cross account access. 477 | 478 | Default is `["bucket-owner-full-control"]`. 479 | 480 | #### Cloudfront Origin Access Identity Access 481 | 482 | - [**`create_origin_access_identity`**](#var-create_origin_access_identity): *(Optional `bool`)* 483 | 484 | Specifies whether to create and origin access identity and grant it access to read 485 | from the bucket. This can be used to grant a Cloudfront Distribution access to 486 | bucket objects when specifying this bucket as an origin. 487 | The Cloudfront Distribution must be in the same account. 488 | For cross account access create the OAI in the account of the cloudfront distribution and use 489 | `origin_acesss_identities` attribute to enable access. 490 | **Attention:** Objects shared that way need 491 | to be owned by the account the bucket belongs to and can not be owned by other accounts 492 | (e.g. when uploaded through cross-account-access). 493 | 494 | Default is `false`. 495 | 496 | - [**`origin_acesss_identities`**](#var-origin_acesss_identities): *(Optional `list(string)`)* 497 | 498 | Specify a list of Cloudfront OAIs to grant read-only access to. 499 | If in addition a new origin access identity is created via the `create_origin_access_identity` 500 | attribute, all identities will be granted access. 501 | **Attention:** Objects shared that way need 502 | to be owned by the account the bucket belongs to and can not be owned by other accounts 503 | (e.g. when uploaded through cross-account-access). 504 | 505 | Default is `[]`. 506 | 507 | #### ELB Log Delivery 508 | 509 | - [**`elb_log_delivery`**](#var-elb_log_delivery): *(Optional `bool`)* 510 | 511 | Allow delivery of logs from Elastic Loadbalancers (ELB). 512 | 513 | - [**`elb_regions`**](#var-elb_regions): *(Optional `list(string)`)* 514 | 515 | The names of the region whose AWS ELB account IDs are desired. 516 | Default is the region from the AWS provider configuration. 517 | 518 | Default is `[]`. 519 | 520 | ### Module Configuration 521 | 522 | - [**`module_enabled`**](#var-module_enabled): *(Optional `bool`)* 523 | 524 | Specifies whether resources in the module will be created. 525 | 526 | Default is `true`. 527 | 528 | - [**`module_tags`**](#var-module_tags): *(Optional `map(string)`)* 529 | 530 | A map of tags that will be applied to all created resources that accept tags. Tags defined with 'module_tags' can be 531 | overwritten by resource-specific tags. 532 | 533 | Default is `{}`. 534 | 535 | - [**`module_depends_on`**](#var-module_depends_on): *(Optional `list(any)`)* 536 | 537 | A list of dependencies. Any object can be _assigned_ to this list to define a hidden external dependency. 538 | 539 | ## Module Outputs 540 | 541 | The following attributes are exported by the module: 542 | 543 | - [**`module_enabled`**](#output-module_enabled): *(`bool`)* 544 | 545 | Whether this module is enabled. 546 | 547 | - [**`bucket`**](#output-bucket): *(`object(bucket)`)* 548 | 549 | All bucket attributes as returned by the `aws_s3_bucket` resource 550 | containing all arguments as specified above and the other attributes as 551 | specified below. 552 | 553 | - [**`id`**](#output-id): *(`string`)* 554 | 555 | The name of the bucket. 556 | 557 | - [**`arn`**](#output-arn): *(`string`)* 558 | 559 | The ARN of the bucket. Will be of format `arn:aws:s3:::bucketname`. 560 | 561 | - [**`bucket_domain_name`**](#output-bucket_domain_name): *(`string`)* 562 | 563 | The bucket domain name. Will be of format `bucketname.s3.amazonaws.com`. 564 | 565 | - [**`bucket_regional_domain_name`**](#output-bucket_regional_domain_name): *(`string`)* 566 | 567 | The bucket region-specific domain name. The bucket domain name including 568 | the region name, please refer here for format. Note: The AWS CloudFront 569 | allows specifying S3 region-specific endpoint when creating S3 origin, 570 | it will prevent redirect issues from CloudFront to S3 Origin URL. 571 | 572 | - [**`hosted_zone_id`**](#output-hosted_zone_id): *(`string`)* 573 | 574 | The Route 53 Hosted Zone ID for this bucket's region. 575 | 576 | - [**`region`**](#output-region): *(`string`)* 577 | 578 | The AWS region this bucket resides in. 579 | 580 | - [**`bucket_policy`**](#output-bucket_policy): *(`object(bucket_policy)`)* 581 | 582 | All bucket policy object attributes as returned by the `s3_bucket_policy` 583 | resource. 584 | 585 | - [**`origin_access_identity`**](#output-origin_access_identity): *(`object(origin_access_identity)`)* 586 | 587 | All cloudfront origin access identity object attributes as returned by 588 | the `aws_cloudfront_origin_access_identity` resource. 589 | 590 | - [**`access_point`**](#output-access_point): *(`list(access_point)`)* 591 | 592 | A list of `aws_s3_access_point` objects keyed by the `name` attribute. 593 | 594 | ## External Documentation 595 | 596 | ### AWS Documentation S3 597 | 598 | - Access Points: https://docs.aws.amazon.com/AmazonS3/latest/dev/access-points.html 599 | - Default Encryption: https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html 600 | - Optimizing Performance: https://docs.aws.amazon.com/AmazonS3/latest/dev/optimizing-performance.html 601 | - Requester Pays Bucket: https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html 602 | - Security: https://docs.aws.amazon.com/AmazonS3/latest/dev/security.html 603 | 604 | ### Terraform AWS Provider Documentation 605 | 606 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket 607 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_access_point 608 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy 609 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_object 610 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block 611 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_identity 612 | 613 | ## Module Versioning 614 | 615 | This Module follows the principles of [Semantic Versioning (SemVer)]. 616 | 617 | Given a version number `MAJOR.MINOR.PATCH`, we increment the: 618 | 619 | 1. `MAJOR` version when we make incompatible changes, 620 | 2. `MINOR` version when we add functionality in a backwards compatible manner, and 621 | 3. `PATCH` version when we make backwards compatible bug fixes. 622 | 623 | ### Backwards compatibility in `0.0.z` and `0.y.z` version 624 | 625 | - Backwards compatibility in versions `0.0.z` is **not guaranteed** when `z` is increased. (Initial development) 626 | - Backwards compatibility in versions `0.y.z` is **not guaranteed** when `y` is increased. (Pre-release) 627 | 628 | ## About Mineiros 629 | 630 | [Mineiros][homepage] is a remote-first company headquartered in Berlin, Germany 631 | that solves development, automation and security challenges in cloud infrastructure. 632 | 633 | Our vision is to massively reduce time and overhead for teams to manage and 634 | deploy production-grade and secure cloud infrastructure. 635 | 636 | We offer commercial support for all of our modules and encourage you to reach out 637 | if you have any questions or need help. Feel free to email us at [hello@mineiros.io] or join our 638 | [Community Slack channel][slack]. 639 | 640 | ## Reporting Issues 641 | 642 | We use GitHub [Issues] to track community reported issues and missing features. 643 | 644 | ## Contributing 645 | 646 | Contributions are always encouraged and welcome! For the process of accepting changes, we use 647 | [Pull Requests]. If you'd like more information, please see our [Contribution Guidelines]. 648 | 649 | ## Makefile Targets 650 | 651 | This repository comes with a handy [Makefile]. 652 | Run `make help` to see details on each available target. 653 | 654 | ## License 655 | 656 | [![license][badge-license]][apache20] 657 | 658 | This module is licensed under the Apache License Version 2.0, January 2004. 659 | Please see [LICENSE] for full details. 660 | 661 | Copyright © 2020-2022 [Mineiros GmbH][homepage] 662 | 663 | 664 | 665 | 666 | [homepage]: https://mineiros.io/?ref=terraform-aws-s3-bucket 667 | [hello@mineiros.io]: mailto:hello@mineiros.io 668 | [badge-build]: https://github.com/mineiros-io/terraform-aws-s3-bucket/workflows/CI/CD%20Pipeline/badge.svg 669 | [badge-semver]: https://img.shields.io/github/v/tag/mineiros-io/terraform-aws-s3-bucket.svg?label=latest&sort=semver 670 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 671 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform 672 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 673 | [badge-tf-aws]: https://img.shields.io/badge/AWS-3%20and%202.0+-F8991D.svg?logo=terraform 674 | [releases-aws-provider]: https://github.com/terraform-providers/terraform-provider-aws/releases 675 | [build-status]: https://github.com/mineiros-io/terraform-aws-s3-bucket/actions 676 | [releases-github]: https://github.com/mineiros-io/terraform-aws-s3-bucket/releases 677 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 678 | [apache20]: https://opensource.org/licenses/Apache-2.0 679 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 680 | [Terraform]: https://www.terraform.io 681 | [AWS S3-Bucket]: https://aws.amazon.com/s3/ 682 | [Semantic Versioning (SemVer)]: https://semver.org/ 683 | [AWS IAM Policy Document Guide]: https://learn.hashicorp.com/terraform/aws/iam-policy 684 | [Requester Pays Buckets developer guide]: https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html 685 | [examples/secure-s3-bucket/main.tf]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/examples/secure-s3-bucket/main.tf 686 | [variables.tf]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/variables.tf 687 | [examples/]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/examples 688 | [Issues]: https://github.com/mineiros-io/terraform-aws-s3-bucket/issues 689 | [LICENSE]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/LICENSE 690 | [Makefile]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/Makefile 691 | [Pull Requests]: https://github.com/mineiros-io/terraform-aws-s3-bucket/pulls 692 | [Contribution Guidelines]: https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/CONTRIBUTING.md 693 | -------------------------------------------------------------------------------- /README.tfdoc.hcl: -------------------------------------------------------------------------------- 1 | header { 2 | image = "https://raw.githubusercontent.com/mineiros-io/brand/3bffd30e8bdbbde32c143e2650b2faa55f1df3ea/mineiros-primary-logo.svg" 3 | url = "https://mineiros.io/?ref=terraform-aws-s3-bucket" 4 | 5 | badge "build" { 6 | image = "https://github.com/mineiros-io/terraform-aws-s3-bucket/workflows/CI/CD%20Pipeline/badge.svg" 7 | url = "https://github.com/mineiros-io/terraform-aws-s3-bucket/actions" 8 | text = "Build Status" 9 | } 10 | 11 | badge "semver" { 12 | image = "https://img.shields.io/github/v/tag/mineiros-io/terraform-aws-s3-bucket.svg?label=latest&sort=semver" 13 | url = "https://github.com/mineiros-io/terraform-aws-s3-bucket/releases" 14 | text = "GitHub tag (latest SemVer)" 15 | } 16 | 17 | badge "terraform" { 18 | image = "https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform" 19 | url = "https://github.com/hashicorp/terraform/releases" 20 | text = "Terraform Version" 21 | } 22 | 23 | badge "tf-aws-provider" { 24 | image = "https://img.shields.io/badge/AWS-3%20and%202.0+-F8991D.svg?logo=terraform" 25 | url = "https://github.com/terraform-providers/terraform-provider-aws/releases" 26 | text = "AWS Provider Version" 27 | } 28 | 29 | badge "slack" { 30 | image = "https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack" 31 | url = "https://mineiros.io/slack" 32 | text = "Join Slack" 33 | } 34 | } 35 | 36 | section { 37 | title = "terraform-aws-s3-bucket" 38 | toc = true 39 | content = <<-END 40 | A [Terraform] base module for creating a secure [AWS S3-Bucket]. 41 | 42 | ***This module supports Terraform v1.x, v0.15, v0.14, v0.13 as well as v0.12.20 and above 43 | and is compatible with the terraform AWS provider v3 as well as v2.0 and above.*** 44 | END 45 | 46 | section { 47 | title = "Module Features" 48 | content = <<-END 49 | In contrast to the plain `aws_s3_bucket` resource this module creates secure 50 | buckets by default. While all security features can be disabled as needed, best practices 51 | are pre-configured. 52 | 53 | In addition to security, easy cross-account access can be granted to the objects 54 | of the bucket enforcing `bucket-owner-full-control` ACL for objects created by other accounts. 55 | 56 | - **Default Security Settings**: 57 | Bucket public access blocking all set to `true` by default, 58 | Server-Side-Encryption (SSE) at rest `enabled` by default (AES256), 59 | Bucket ACL defaults to canned `private` ACL 60 | 61 | - **Standard S3 Features**: 62 | Server-Side-Encryption (SSE) enabled by default, 63 | Versioning, 64 | Bucket Logging, 65 | Lifecycle Rules, 66 | Request Payer, 67 | Cross-Origin Resource Sharing (CORS), 68 | Acceleration Status, 69 | Bucket Policy, 70 | Tags 71 | 72 | - **Extended S3 Features**: 73 | Bucket Public Access Blocking, 74 | S3 Access Points 75 | 76 | - **Additional Features**: 77 | Cross-Account access policy with forced `bucket-owner-full-control` ACL for direct access, 78 | Create Cloudfront Origin Access Identity (OAI) and grant read-only access, 79 | Grant read-only access to existing Cloudfront Origin Access Identity (OAI), 80 | Allow ELB log delivery 81 | 82 | - *Features not yet implemented*: 83 | Enforce Encryption via a policy that blocks unencrypted uploads, 84 | ACL policy grants (aws-provider >= 2.52.0), 85 | Amazon S3 Analytics (aws-provider >= 2.49.0), 86 | Replication Configuration, 87 | Website Configuration, 88 | S3 Object Locking, 89 | Bucket Notifications, 90 | Bucket Metrics, 91 | Bucket Inventory, 92 | Generate Cross-Account role for OAI enabled buckets if desired, 93 | Generate KMS key to encrypt objects at rest if desired 94 | END 95 | } 96 | 97 | section { 98 | title = "Getting Started" 99 | content = <<-END 100 | Most basic usage creating a random named secure AWS bucket. 101 | 102 | ```hcl 103 | module "bucket" { 104 | source = "mineiros-io/s3-bucket/aws" 105 | version = "~> 0.6.0" 106 | } 107 | ``` 108 | 109 | Advanced usage as found in [examples/secure-s3-bucket/main.tf] setting all required and optional arguments to their default values. 110 | END 111 | } 112 | 113 | section { 114 | title = "Module Argument Reference" 115 | content = <<-END 116 | See [variables.tf] and [examples/] for details and use-cases. 117 | END 118 | 119 | section { 120 | title = "Bucket Configuration" 121 | 122 | variable "bucket" { 123 | type = string 124 | description = <<-END 125 | The name of the bucket. If omitted, Terraform will assign a random, unique name. Forces new resource. 126 | END 127 | } 128 | 129 | variable "bucket_prefix" { 130 | type = string 131 | description = <<-END 132 | Creates a unique bucket name beginning with the specified prefix. Conflicts with `bucket`. Forces new resource. 133 | END 134 | } 135 | 136 | variable "acl" { 137 | type = string 138 | default = "private" 139 | description = <<-END 140 | The canned ACL to apply. 141 | END 142 | } 143 | 144 | variable "policy" { 145 | type = string 146 | default = null 147 | description = <<-END 148 | A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide]. 149 | END 150 | } 151 | 152 | variable "tags" { 153 | type = map(string) 154 | default = {} 155 | description = <<-END 156 | A mapping of tags to assign to the bucket. 157 | END 158 | } 159 | 160 | variable "force_destroy" { 161 | type = bool 162 | default = false 163 | description = <<-END 164 | A boolean that indicates all objects (including any locked objects) should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable. 165 | END 166 | } 167 | 168 | variable "acceleration_status" { 169 | type = string 170 | description = <<-END 171 | Sets the accelerate configuration of an existing bucket. Can be `Enabled` or `Suspended`. 172 | END 173 | } 174 | 175 | variable "request_payer" { 176 | type = string 177 | default = "BucketOwner" 178 | description = <<-END 179 | Specifies who should bear the cost of Amazon S3 data transfer. Can be either `BucketOwner` or `Requester`. 180 | By default, the owner of the S3 bucket would incur the costs of any data transfer. 181 | See [Requester Pays Buckets developer guide] for more information. 182 | END 183 | } 184 | 185 | variable "cors_rule" { 186 | type = object(cors) 187 | default = {} 188 | description = <<-END 189 | Specifying settings for Cross-Origin Resource Sharing (CORS) (documented below). 190 | END 191 | 192 | attribute "allowed_headers" { 193 | type = list(string) 194 | default = [] 195 | description = <<-END 196 | Specifies which headers are allowed. 197 | END 198 | } 199 | 200 | attribute "allowed_methods" { 201 | required = true 202 | type = list(string) 203 | description = <<-END 204 | Specifies which methods are allowed. Can be `GET`, `PUT`, `POST`, `DELETE` or `HEAD`. 205 | END 206 | } 207 | 208 | attribute "allowed_origins" { 209 | required = true 210 | type = list(string) 211 | description = <<-END 212 | Specifies which origins are allowed. 213 | END 214 | } 215 | 216 | attribute "expose_headers" { 217 | type = list(string) 218 | default = [] 219 | description = <<-END 220 | Specifies expose header in the response. 221 | END 222 | } 223 | 224 | attribute "max_age_seconds" { 225 | type = number 226 | description = <<-END 227 | Specifies time in seconds that browser can cache the response for a preflight request. 228 | END 229 | } 230 | } 231 | 232 | variable "versioning" { 233 | type = bool 234 | default = false 235 | description = <<-END 236 | Can also be of type `object`. When set to `true` versioning will be enabled. Specifies Versioning Configuration when passed as an object (documented below). 237 | END 238 | 239 | attribute "enabled" { 240 | type = bool 241 | description = <<-END 242 | Once you version-enable a bucket, it can never return to an unversioned state. 243 | You can, however, suspend versioning on that bucket. 244 | END 245 | } 246 | 247 | attribute "mfa_delete" { 248 | type = bool 249 | default = false 250 | description = <<-END 251 | Enable MFA delete for either change: the versioning state of your bucket or 252 | permanently delete an object version. 253 | END 254 | } 255 | } 256 | 257 | variable "logging" { 258 | type = map(string) 259 | default = {} 260 | description = <<-END 261 | Specifying a configuration for logging access logs (documented below). 262 | END 263 | 264 | attribute "target_bucket" { 265 | required = true 266 | type = string 267 | description = <<-END 268 | The name of the bucket that will receive the log objects. 269 | END 270 | } 271 | 272 | attribute "target_prefix" { 273 | type = string 274 | description = <<-END 275 | To specify a key prefix for log objects. 276 | END 277 | } 278 | } 279 | 280 | variable "apply_server_side_encryption_by_default" { 281 | type = map(string) 282 | description = <<-END 283 | Specifying the server side encryption to apply to objects at rest (documented below). 284 | Default is to use `AES256` encryption. 285 | END 286 | 287 | attribute "sse_algorithm" { 288 | type = string 289 | default = "aws:kms" 290 | description = <<-END 291 | The server-side encryption algorithm to use. Valid values are `AES256` and `aws:kms`. Default applies when `kms_master_key_id` is specified, else `AES256` 292 | END 293 | } 294 | 295 | attribute "kms_master_key_id" { 296 | type = string 297 | default = "null" 298 | description = <<-END 299 | The AWS KMS master key ID used for the SSE-KMS encryption. The default `aws/s3` AWS KMS master key is used if this element is absent while the sse_algorithm is `aws:kms`. 300 | END 301 | } 302 | } 303 | 304 | variable "lifecycle_rules" { 305 | type = list(lifecycle_rule) 306 | default = [] 307 | description = <<-END 308 | Specifying various rules specifying object lifecycle management (documented below). 309 | END 310 | 311 | attribute "id" { 312 | type = string 313 | description = <<-END 314 | Unique identifier for the rule. 315 | END 316 | } 317 | 318 | attribute "prefix" { 319 | type = string 320 | description = <<-END 321 | Object key prefix identifying one or more objects to which the rule applies. 322 | END 323 | } 324 | 325 | attribute "tags" { 326 | type = map(string) 327 | description = <<-END 328 | Specifies object tags key and value. 329 | END 330 | } 331 | 332 | attribute "enabled" { 333 | required = true 334 | type = bool 335 | description = <<-END 336 | Specifies lifecycle rule status. 337 | END 338 | } 339 | 340 | attribute "abort_incomplete_multipart_upload_days" { 341 | type = number 342 | description = <<-END 343 | Specifies the number of days after initiating a multipart upload when the multipart upload must be completed. 344 | END 345 | } 346 | 347 | attribute "expiration" { 348 | type = object(expiration) 349 | description = <<-END 350 | Specifies a period in the object's expire (documented below). 351 | END 352 | 353 | attribute "date" { 354 | type = string 355 | description = <<-END 356 | Specifies the date after which you want the corresponding action to take effect. 357 | END 358 | } 359 | 360 | attribute "days" { 361 | type = string 362 | description = <<-END 363 | Specifies the number of days after object creation when the specific rule action takes effect. 364 | END 365 | } 366 | 367 | attribute "expired_object_delete_marker" { 368 | type = bool 369 | description = <<-END 370 | On a versioned bucket (versioning-enabled or versioning-suspended bucket), you can add this element in the lifecycle configuration to direct Amazon S3 to delete expired object delete markers. 371 | END 372 | } 373 | } 374 | 375 | attribute "transition" { 376 | type = object(transition) 377 | description = <<-END 378 | Specifies a period in the object's transitions (documented below). 379 | END 380 | 381 | attribute "date" { 382 | type = string 383 | description = <<-END 384 | Specifies the date after which you want the corresponding action to take effect. 385 | END 386 | } 387 | 388 | attribute "days" { 389 | type = number 390 | description = <<-END 391 | Specifies the number of days after object creation when the specific rule action takes effect. 392 | END 393 | } 394 | 395 | attribute "storage_class" { 396 | required = true 397 | type = string 398 | description = <<-END 399 | Specifies the Amazon S3 storage class to which you want the object to transition. 400 | Can be `ONEZONE_IA`, `STANDARD_IA`, `INTELLIGENT_TIERING`, `GLACIER`, or `DEEP_ARCHIVE`. 401 | END 402 | } 403 | } 404 | 405 | attribute "noncurrent_version_expiration" { 406 | type = object(noncurrent_version_expiration) 407 | description = <<-END 408 | Specifies when noncurrent object versions expire (documented below). 409 | END 410 | 411 | attribute "days" { 412 | required = true 413 | type = number 414 | description = <<-END 415 | Specifies the number of days an object's noncurrent object versions expire. 416 | END 417 | } 418 | } 419 | 420 | attribute "noncurrent_version_transition" { 421 | type = object(noncurrent_version_transition) 422 | description = <<-END 423 | Specifies when noncurrent object versions transitions (documented below). 424 | At least one of `expiration`, `transition`, `noncurrent_version_expiration`, `noncurrent_version_transition` must be specified. 425 | END 426 | 427 | attribute "days" { 428 | required = true 429 | type = number 430 | description = <<-END 431 | Specifies the number of days an object's noncurrent object versions expire. 432 | END 433 | } 434 | 435 | attribute "storage_class" { 436 | required = true 437 | type = string 438 | description = <<-END 439 | Specifies the Amazon S3 storage class to which you want the noncurrent versions object to transition. 440 | Can be `ONEZONE_IA`, `STANDARD_IA`, `INTELLIGENT_TIERING`, `GLACIER`, or `DEEP_ARCHIVE`. 441 | END 442 | } 443 | } 444 | } 445 | } 446 | 447 | section { 448 | title = "Extended Resource Configuration" 449 | 450 | section { 451 | title = "S3 Access Points" 452 | 453 | variable "access_points" { 454 | type = list(access_point) 455 | default = [] 456 | description = <<-END 457 | Amazon S3 Access Points simplify managing data access at scale for shared datasets in S3. 458 | Access points are named network endpoints that are attached to buckets that 459 | you can use to perform S3 object operations, such as `GetObject` and `PutObject`. 460 | Each access point has distinct permissions and network controls that S3 applies 461 | for any request that is made through that access point. 462 | Each access point enforces a customized access point policy that works in 463 | conjunction with the bucket policy that is attached to the underlying bucket. 464 | You can configure any access point to accept requests only from a 465 | virtual private cloud (VPC) to restrict Amazon S3 data access to a private network. 466 | You can also configure custom block public access settings for each access point. 467 | END 468 | 469 | attribute "name" { 470 | required = true 471 | type = string 472 | description = <<-END 473 | The name you want to assign to this access point. 474 | END 475 | } 476 | 477 | attribute "account_id" { 478 | type = string 479 | description = <<-END 480 | The AWS account ID for the owner of the bucket for which you want to create an access point. 481 | Defaults to automatically determined account ID of the Terraform AWS provider. 482 | END 483 | } 484 | 485 | attribute "policy" { 486 | type = string 487 | description = <<-END 488 | A valid JSON document that specifies the policy that you want to apply to this access point. 489 | END 490 | } 491 | 492 | attribute "vpc_id" { 493 | type = string 494 | description = <<-END 495 | If set, this access point will only allow connections from the specified VPC ID. 496 | END 497 | } 498 | 499 | attribute "block_public_acls" { 500 | type = bool 501 | default = true 502 | description = <<-END 503 | Whether Amazon S3 should block public ACLs for this bucket. 504 | Enabling this setting does not affect existing policies or ACLs. 505 | END 506 | } 507 | 508 | attribute "block_public_policy" { 509 | type = bool 510 | default = true 511 | description = <<-END 512 | Whether Amazon S3 should block public bucket policies for this bucket. 513 | Enabling this setting does not affect the existing bucket policy. 514 | If `true`: 515 | - Reject calls to `PUT Bucket policy` if the specified bucket policy allows public access. 516 | END 517 | } 518 | 519 | attribute "ignore_public_acls" { 520 | type = bool 521 | default = true 522 | description = <<-END 523 | Whether Amazon S3 should ignore public ACLs for this bucket. 524 | Enabling this setting does not affect the persistence of any existing ACLs and 525 | doesn't prevent new public ACLs from being set. 526 | If `true`: 527 | - Ignore public ACLs on this bucket and any objects that it contains. 528 | END 529 | } 530 | 531 | attribute "restrict_public_buckets" { 532 | type = bool 533 | default = true 534 | description = <<-END 535 | Whether Amazon S3 should restrict public bucket policies for this bucket. 536 | Enabling this setting does not affect the previously stored bucket policy, 537 | except that public and cross-account access within the public bucket policy, 538 | including non-public delegation to specific accounts, is blocked. 539 | If `true`: 540 | - Only the bucket owner and AWS Services can access this buckets if it has a public policy. 541 | END 542 | } 543 | } 544 | } 545 | 546 | section { 547 | title = "S3 bucket-level Public Access Block Configuration" 548 | 549 | variable "block_public_acls" { 550 | type = bool 551 | default = true 552 | description = <<-END 553 | Whether Amazon S3 should block public ACLs for this bucket. 554 | Enabling this setting does not affect existing policies or ACLs. 555 | If `true`: 556 | - `PUT Bucket acl` and `PUT Object acl` calls will fail if the specified ACL allows public access. 557 | - `PUT Object` calls will fail if the request includes an object ACL. 558 | END 559 | } 560 | 561 | variable "block_public_policy" { 562 | type = bool 563 | default = true 564 | description = <<-END 565 | Whether Amazon S3 should block public bucket policies for this bucket. 566 | Enabling this setting does not affect the existing bucket policy. 567 | If `true`: 568 | - Reject calls to `PUT Bucket policy` if the specified bucket policy allows public access. 569 | END 570 | } 571 | 572 | variable "ignore_public_acls" { 573 | type = bool 574 | default = true 575 | description = <<-END 576 | Whether Amazon S3 should ignore public ACLs for this bucket. 577 | Enabling this setting does not affect the persistence of any existing ACLs and 578 | doesn't prevent new public ACLs from being set. 579 | If `true`: 580 | - Ignore public ACLs on this bucket and any objects that it contains. 581 | END 582 | } 583 | 584 | variable "restrict_public_buckets" { 585 | type = bool 586 | default = true 587 | description = <<-END 588 | Whether Amazon S3 should restrict public bucket policies for this bucket. 589 | Enabling this setting does not affect the previously stored bucket policy, 590 | except that public and cross-account access within the public bucket policy, 591 | including non-public delegation to specific accounts, is blocked. 592 | If `true`: 593 | - Only the bucket owner and AWS Services can access this buckets if it has a public policy. 594 | END 595 | } 596 | } 597 | 598 | section { 599 | title = "Cross Account Access Configuration" 600 | 601 | variable "cross_account_identifiers" { 602 | type = list(string) 603 | default = [] 604 | description = <<-END 605 | Specifies identifiers that should be granted cross account access to. 606 | If this list is empty Cross Account Access is not configured and all other 607 | options in this category are ignored. 608 | END 609 | } 610 | 611 | variable "cross_account_bucket_actions" { 612 | type = list(string) 613 | default = ["s3:ListBucket"] 614 | description = <<-END 615 | Specifies actions on the bucket to grant from cross account. 616 | END 617 | } 618 | 619 | variable "cross_account_object_actions" { 620 | type = list(string) 621 | default = ["s3:GetObject"] 622 | description = <<-END 623 | Specifies actions on bucket objects to grant from cross account. 624 | END 625 | } 626 | 627 | variable "cross_account_object_actions_with_forced_acl" { 628 | type = list(string) 629 | default = ["s3:PutObject", "s3:PutObjectAcl"] 630 | description = <<-END 631 | Specifies actions on bucket objects to grant only with foreced ACL from cross account. 632 | END 633 | } 634 | 635 | variable "cross_account_forced_acls" { 636 | type = list(string) 637 | default = ["bucket-owner-full-control"] 638 | description = <<-END 639 | Specifies ACLs to force on new objects for cross account access. 640 | END 641 | } 642 | } 643 | 644 | section { 645 | title = "Cloudfront Origin Access Identity Access" 646 | 647 | variable "create_origin_access_identity" { 648 | type = bool 649 | default = false 650 | description = <<-END 651 | Specifies whether to create and origin access identity and grant it access to read 652 | from the bucket. This can be used to grant a Cloudfront Distribution access to 653 | bucket objects when specifying this bucket as an origin. 654 | The Cloudfront Distribution must be in the same account. 655 | For cross account access create the OAI in the account of the cloudfront distribution and use 656 | `origin_acesss_identities` attribute to enable access. 657 | **Attention:** Objects shared that way need 658 | to be owned by the account the bucket belongs to and can not be owned by other accounts 659 | (e.g. when uploaded through cross-account-access). 660 | END 661 | } 662 | 663 | variable "origin_acesss_identities" { 664 | type = list(string) 665 | default = [] 666 | description = <<-END 667 | Specify a list of Cloudfront OAIs to grant read-only access to. 668 | If in addition a new origin access identity is created via the `create_origin_access_identity` 669 | attribute, all identities will be granted access. 670 | **Attention:** Objects shared that way need 671 | to be owned by the account the bucket belongs to and can not be owned by other accounts 672 | (e.g. when uploaded through cross-account-access). 673 | END 674 | } 675 | } 676 | 677 | section { 678 | title = "ELB Log Delivery" 679 | 680 | variable "elb_log_delivery" { 681 | type = bool 682 | description = <<-END 683 | Allow delivery of logs from Elastic Loadbalancers (ELB). 684 | END 685 | } 686 | 687 | variable "elb_regions" { 688 | type = list(string) 689 | default = [] 690 | description = <<-END 691 | The names of the region whose AWS ELB account IDs are desired. 692 | Default is the region from the AWS provider configuration. 693 | END 694 | } 695 | } 696 | } 697 | 698 | section { 699 | title = "Module Configuration" 700 | 701 | variable "module_enabled" { 702 | type = bool 703 | default = true 704 | description = <<-END 705 | Specifies whether resources in the module will be created. 706 | END 707 | } 708 | 709 | variable "module_tags" { 710 | type = map(string) 711 | default = {} 712 | description = <<-END 713 | A map of tags that will be applied to all created resources that accept tags. Tags defined with 'module_tags' can be 714 | overwritten by resource-specific tags. 715 | END 716 | } 717 | 718 | variable "module_depends_on" { 719 | type = list(any) 720 | description = <<-END 721 | A list of dependencies. Any object can be _assigned_ to this list to define a hidden external dependency. 722 | END 723 | } 724 | } 725 | 726 | } 727 | 728 | section { 729 | title = "Module Outputs" 730 | content = <<-END 731 | The following attributes are exported by the module: 732 | END 733 | 734 | output "module_enabled" { 735 | type = bool 736 | description = <<-END 737 | Whether this module is enabled. 738 | END 739 | } 740 | 741 | output "bucket" { 742 | type = object(bucket) 743 | description = <<-END 744 | All bucket attributes as returned by the `aws_s3_bucket` resource 745 | containing all arguments as specified above and the other attributes as 746 | specified below. 747 | END 748 | } 749 | 750 | output "id" { 751 | type = string 752 | description = <<-END 753 | The name of the bucket. 754 | END 755 | } 756 | 757 | output "arn" { 758 | type = string 759 | description = <<-END 760 | The ARN of the bucket. Will be of format `arn:aws:s3:::bucketname`. 761 | END 762 | } 763 | 764 | output "bucket_domain_name" { 765 | type = string 766 | description = <<-END 767 | The bucket domain name. Will be of format `bucketname.s3.amazonaws.com`. 768 | END 769 | } 770 | 771 | output "bucket_regional_domain_name" { 772 | type = string 773 | description = <<-END 774 | The bucket region-specific domain name. The bucket domain name including 775 | the region name, please refer here for format. Note: The AWS CloudFront 776 | allows specifying S3 region-specific endpoint when creating S3 origin, 777 | it will prevent redirect issues from CloudFront to S3 Origin URL. 778 | END 779 | } 780 | 781 | output "hosted_zone_id" { 782 | type = string 783 | description = <<-END 784 | The Route 53 Hosted Zone ID for this bucket's region. 785 | END 786 | } 787 | 788 | output "region" { 789 | type = string 790 | description = <<-END 791 | The AWS region this bucket resides in. 792 | END 793 | } 794 | 795 | output "bucket_policy" { 796 | type = object(bucket_policy) 797 | description = <<-END 798 | All bucket policy object attributes as returned by the `s3_bucket_policy` 799 | resource. 800 | END 801 | } 802 | 803 | output "origin_access_identity" { 804 | type = object(origin_access_identity) 805 | description = <<-END 806 | All cloudfront origin access identity object attributes as returned by 807 | the `aws_cloudfront_origin_access_identity` resource. 808 | END 809 | } 810 | 811 | output "access_point" { 812 | type = list(access_point) 813 | description = <<-END 814 | A list of `aws_s3_access_point` objects keyed by the `name` attribute. 815 | END 816 | } 817 | } 818 | 819 | section { 820 | title = "External Documentation" 821 | 822 | section { 823 | title = "AWS Documentation S3" 824 | content = <<-END 825 | - Access Points: https://docs.aws.amazon.com/AmazonS3/latest/dev/access-points.html 826 | - Default Encryption: https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html 827 | - Optimizing Performance: https://docs.aws.amazon.com/AmazonS3/latest/dev/optimizing-performance.html 828 | - Requester Pays Bucket: https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html 829 | - Security: https://docs.aws.amazon.com/AmazonS3/latest/dev/security.html 830 | END 831 | } 832 | 833 | section { 834 | title = "Terraform AWS Provider Documentation" 835 | content = <<-END 836 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket 837 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_access_point 838 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy 839 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_object 840 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block 841 | - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_identity 842 | END 843 | } 844 | } 845 | 846 | section { 847 | title = "Module Versioning" 848 | content = <<-END 849 | This Module follows the principles of [Semantic Versioning (SemVer)]. 850 | 851 | Given a version number `MAJOR.MINOR.PATCH`, we increment the: 852 | 853 | 1. `MAJOR` version when we make incompatible changes, 854 | 2. `MINOR` version when we add functionality in a backwards compatible manner, and 855 | 3. `PATCH` version when we make backwards compatible bug fixes. 856 | END 857 | 858 | section { 859 | title = "Backwards compatibility in `0.0.z` and `0.y.z` version" 860 | content = <<-END 861 | - Backwards compatibility in versions `0.0.z` is **not guaranteed** when `z` is increased. (Initial development) 862 | - Backwards compatibility in versions `0.y.z` is **not guaranteed** when `y` is increased. (Pre-release) 863 | END 864 | } 865 | } 866 | 867 | section { 868 | title = "About Mineiros" 869 | content = <<-END 870 | [Mineiros][homepage] is a remote-first company headquartered in Berlin, Germany 871 | that solves development, automation and security challenges in cloud infrastructure. 872 | 873 | Our vision is to massively reduce time and overhead for teams to manage and 874 | deploy production-grade and secure cloud infrastructure. 875 | 876 | We offer commercial support for all of our modules and encourage you to reach out 877 | if you have any questions or need help. Feel free to email us at [hello@mineiros.io] or join our 878 | [Community Slack channel][slack]. 879 | END 880 | } 881 | 882 | section { 883 | title = "Reporting Issues" 884 | content = <<-END 885 | We use GitHub [Issues] to track community reported issues and missing features. 886 | END 887 | } 888 | 889 | section { 890 | title = "Contributing" 891 | content = <<-END 892 | Contributions are always encouraged and welcome! For the process of accepting changes, we use 893 | [Pull Requests]. If you'd like more information, please see our [Contribution Guidelines]. 894 | END 895 | } 896 | 897 | section { 898 | title = "Makefile Targets" 899 | content = <<-END 900 | This repository comes with a handy [Makefile]. 901 | Run `make help` to see details on each available target. 902 | END 903 | } 904 | 905 | section { 906 | title = "License" 907 | content = <<-END 908 | [![license][badge-license]][apache20] 909 | 910 | This module is licensed under the Apache License Version 2.0, January 2004. 911 | Please see [LICENSE] for full details. 912 | 913 | Copyright © 2020-2022 [Mineiros GmbH][homepage] 914 | END 915 | } 916 | } 917 | 918 | references { 919 | ref "homepage" { 920 | value = "https://mineiros.io/?ref=terraform-aws-s3-bucket" 921 | } 922 | ref "hello@mineiros.io" { 923 | value = "mailto:hello@mineiros.io" 924 | } 925 | ref "badge-build" { 926 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/workflows/CI/CD%20Pipeline/badge.svg" 927 | } 928 | ref "badge-semver" { 929 | value = "https://img.shields.io/github/v/tag/mineiros-io/terraform-aws-s3-bucket.svg?label=latest&sort=semver" 930 | } 931 | ref "badge-license" { 932 | value = "https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg" 933 | } 934 | ref "badge-terraform" { 935 | value = "https://img.shields.io/badge/terraform-1.x%20|%200.15%20|%200.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform" 936 | } 937 | ref "badge-slack" { 938 | value = "https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack" 939 | } 940 | ref "badge-tf-aws" { 941 | value = "https://img.shields.io/badge/AWS-3%20and%202.0+-F8991D.svg?logo=terraform" 942 | } 943 | ref "releases-aws-provider" { 944 | value = "https://github.com/terraform-providers/terraform-provider-aws/releases" 945 | } 946 | ref "build-status" { 947 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/actions" 948 | } 949 | ref "releases-github" { 950 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/releases" 951 | } 952 | ref "releases-terraform" { 953 | value = "https://github.com/hashicorp/terraform/releases" 954 | } 955 | ref "apache20" { 956 | value = "https://opensource.org/licenses/Apache-2.0" 957 | } 958 | ref "slack" { 959 | value = "https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg" 960 | } 961 | ref "Terraform" { 962 | value = "https://www.terraform.io" 963 | } 964 | ref "AWS S3-Bucket" { 965 | value = "https://aws.amazon.com/s3/" 966 | } 967 | ref "Semantic Versioning (SemVer)" { 968 | value = "https://semver.org/" 969 | } 970 | ref "AWS IAM Policy Document Guide" { 971 | value = "https://learn.hashicorp.com/terraform/aws/iam-policy" 972 | } 973 | ref "Requester Pays Buckets developer guide" { 974 | value = "https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html" 975 | } 976 | ref "examples/secure-s3-bucket/main.tf" { 977 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/examples/secure-s3-bucket/main.tf" 978 | } 979 | ref "variables.tf" { 980 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/variables.tf" 981 | } 982 | ref "examples/" { 983 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/examples" 984 | } 985 | ref "Issues" { 986 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/issues" 987 | } 988 | ref "LICENSE" { 989 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/LICENSE" 990 | } 991 | ref "Makefile" { 992 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/Makefile" 993 | } 994 | ref "Pull Requests" { 995 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/pulls" 996 | } 997 | ref "Contribution Guidelines" { 998 | value = "https://github.com/mineiros-io/terraform-aws-s3-bucket/blob/master/CONTRIBUTING.md" 999 | } 1000 | } 1001 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= 9 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 10 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 11 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 12 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 13 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 14 | github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 15 | github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 16 | github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 17 | github.com/Azure/azure-sdk-for-go v38.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 18 | github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 19 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 20 | github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= 21 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 22 | github.com/Azure/go-autorest/autorest v0.9.1/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 23 | github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= 24 | github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= 25 | github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= 26 | github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= 27 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 28 | github.com/Azure/go-autorest/autorest/adal v0.6.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= 29 | github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= 30 | github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= 31 | github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= 32 | github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= 33 | github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= 34 | github.com/Azure/go-autorest/autorest/azure/auth v0.3.0/go.mod h1:CI4BQYBct8NS7BXNBBX+RchsFsUu5+oz+OSyR/ZIi7U= 35 | github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= 36 | github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= 37 | github.com/Azure/go-autorest/autorest/azure/cli v0.3.0/go.mod h1:rNYMNAefZMRowqCV0cVhr/YDW5dD7afFq9nXAXL4ykE= 38 | github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= 39 | github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= 40 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 41 | github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= 42 | github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= 43 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 44 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 45 | github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= 46 | github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= 47 | github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= 48 | github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= 49 | github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= 50 | github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= 51 | github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= 52 | github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= 53 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 54 | github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= 55 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 56 | github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 57 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 58 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 59 | github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= 60 | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= 61 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 62 | github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 63 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 64 | github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 65 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 66 | github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= 67 | github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 68 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 69 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 70 | github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 71 | github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= 72 | github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= 73 | github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= 74 | github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= 75 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 76 | github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= 77 | github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 78 | github.com/aws/aws-sdk-go v1.23.8 h1:G/azJoBN0pnhB3B+0eeC4yyVFYIIad6bbzg6wwtImqk= 79 | github.com/aws/aws-sdk-go v1.23.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 80 | github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU= 81 | github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 82 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 83 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 84 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 85 | github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 86 | github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= 87 | github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= 88 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 89 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 90 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 91 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 92 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 93 | github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= 94 | github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 95 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 96 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 97 | github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= 98 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 99 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 100 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 101 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 102 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 103 | github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 104 | github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= 105 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 106 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 107 | github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= 108 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 109 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 110 | github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 111 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 112 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 113 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 114 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 115 | github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= 116 | github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= 117 | github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 118 | github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 119 | github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 120 | github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 121 | github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 122 | github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= 123 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 124 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 125 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 126 | github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 127 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 128 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 129 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 130 | github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 131 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 132 | github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= 133 | github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= 134 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 135 | github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 136 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 137 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 138 | github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 139 | github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 140 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 141 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 142 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 143 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 144 | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 145 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 146 | github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 147 | github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= 148 | github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 149 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 150 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 151 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 152 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 153 | github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= 154 | github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= 155 | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= 156 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 157 | github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= 158 | github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= 159 | github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= 160 | github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= 161 | github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= 162 | github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= 163 | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 164 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 165 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 166 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 167 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 168 | github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 169 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 170 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 171 | github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 172 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 173 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 174 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 175 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 176 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 177 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 178 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 179 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 180 | github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 181 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 182 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 183 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 184 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 185 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 186 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 187 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 188 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 189 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 190 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 191 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 192 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 193 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 194 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 195 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 196 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 197 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 198 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 199 | github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= 200 | github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= 201 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 202 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 203 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 204 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 205 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 206 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 207 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 208 | github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c h1:jWtZjFEUE/Bz0IeIhqCnyZ3HG6KRXSntXe4SjtuTH7c= 209 | github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 210 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 211 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 212 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 213 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 214 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 215 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 216 | github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 217 | github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 218 | github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= 219 | github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= 220 | github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= 221 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 222 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 223 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 224 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 225 | github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 226 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 227 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 228 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 229 | github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= 230 | github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78= 231 | github.com/gruntwork-io/gruntwork-cli v0.5.1/go.mod h1:IBX21bESC1/LGoV7jhXKUnTQTZgQ6dYRsoj/VqxUSZQ= 232 | github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= 233 | github.com/gruntwork-io/terratest v0.23.0 h1:JmGeqO0r5zRLAV55T67NEmPZArz9lN3RKd0moAKhIT4= 234 | github.com/gruntwork-io/terratest v0.23.0/go.mod h1:+fVff0FQYuRzCF3LKpKF9ac+4w384LDcwLZt7O/KmEE= 235 | github.com/gruntwork-io/terratest v0.28.2 h1:M9CMfS/5unIawxYlz55eRDWH16AH522OAJcUc+zsKv4= 236 | github.com/gruntwork-io/terratest v0.28.2/go.mod h1:lTntpr4gGDzb2YEQ1GTjC5G/xw9ixMwxGmZkPCk1O0A= 237 | github.com/gruntwork-io/terratest v0.28.5 h1:B3Cd45sc18V0Ieaw9JrIl/U27c2mPdwc0pOAF3hGMn4= 238 | github.com/gruntwork-io/terratest v0.28.5/go.mod h1:lTntpr4gGDzb2YEQ1GTjC5G/xw9ixMwxGmZkPCk1O0A= 239 | github.com/gruntwork-io/terratest v0.30.0 h1:1USVQG4Rg7Fp5WLuTjgU6kt+o7GM0ZcllYcsKXGv7nI= 240 | github.com/gruntwork-io/terratest v0.30.0/go.mod h1:7dNmTD2zDKUEVqfmvcUU5c9mZi+986mcXNzhzqPYPg8= 241 | github.com/gruntwork-io/terratest v0.34.0 h1:zlDNwYHkjCavF2NWawbEdwEaUJnkyqXCI3P5B0Z3mdM= 242 | github.com/gruntwork-io/terratest v0.34.0/go.mod h1:IBb+b5b7p34oZLfpz/ZADyn8TSKeWSBu+vQMmNeePLE= 243 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 244 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 245 | github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= 246 | github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 247 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 248 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 249 | github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 250 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 251 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 252 | github.com/hashicorp/hcl/v2 v2.8.2 h1:wmFle3D1vu0okesm8BTLVDyJ6/OL9DCLUwn0b2OptiY= 253 | github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= 254 | github.com/hashicorp/terraform-json v0.9.0 h1:WE7+Wt93W93feOiCligElSyS0tlDzwZUtJuDGIBr8zg= 255 | github.com/hashicorp/terraform-json v0.9.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= 256 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 257 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 258 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 259 | github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 260 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 261 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= 262 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= 263 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= 264 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 265 | github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= 266 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 267 | github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 268 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 269 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 270 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 271 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 272 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 273 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 274 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 275 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 276 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 277 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 278 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 279 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 280 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 281 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 282 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 283 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 284 | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 285 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 286 | github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= 287 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 288 | github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= 289 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 290 | github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 291 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 292 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 293 | github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= 294 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 295 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 296 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 297 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 298 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 299 | github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 300 | github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= 301 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= 302 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 303 | github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= 304 | github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 305 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 306 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= 307 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 308 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 309 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 310 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 311 | github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 312 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 313 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 314 | github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 315 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 316 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 317 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 318 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 319 | github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 320 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 321 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 322 | github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 323 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 324 | github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 325 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 326 | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 327 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 328 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 329 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 330 | github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= 331 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 332 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 333 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 334 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 335 | github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 336 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 337 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 338 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 339 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 340 | github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= 341 | github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= 342 | github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= 343 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 344 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 345 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 346 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 347 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 348 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 349 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 350 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 351 | github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= 352 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 353 | github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= 354 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 355 | github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= 356 | github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= 357 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 358 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= 359 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 360 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 361 | github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= 362 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 363 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= 364 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 365 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 366 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 367 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 368 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 369 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 370 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 371 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 372 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 373 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 374 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 375 | github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 376 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 377 | github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 378 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 379 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 380 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 381 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 382 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 383 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 384 | github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 385 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 386 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 387 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 388 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 389 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 390 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 391 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 392 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 393 | github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= 394 | github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 395 | github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= 396 | github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 397 | github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= 398 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 399 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 400 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 401 | github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 402 | github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= 403 | github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 404 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 405 | go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= 406 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 407 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 408 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 409 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 410 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 411 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 412 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 413 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 414 | golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 415 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 416 | golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 417 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 418 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 419 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 420 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 421 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0= 422 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 423 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 424 | golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 425 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= 426 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 427 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 428 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 429 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 430 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 431 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 432 | golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 433 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 434 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 435 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 436 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 437 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 438 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 439 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 440 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 441 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 442 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 443 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 444 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 445 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 446 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 447 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 448 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 449 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 450 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 451 | golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 452 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 453 | golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 454 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 455 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 456 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 457 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 458 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 459 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 460 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 461 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 462 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 463 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 464 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 465 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 466 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 467 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 468 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= 469 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 470 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 471 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 472 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 473 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= 474 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 475 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 476 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 477 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= 478 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 479 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 480 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 481 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 482 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 483 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 484 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 485 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 486 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 487 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 488 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 489 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 490 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 491 | golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 492 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 493 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 494 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 495 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 496 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 497 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 498 | golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 499 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 500 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 501 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 502 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 503 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 504 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 505 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 506 | golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 507 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 508 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 509 | golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 510 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 511 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 512 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 513 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 514 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 515 | golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 516 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 517 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 518 | golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM= 519 | golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 520 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 521 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 522 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50 h1:YvQ10rzcqWXLlJZ3XCUoO25savxmscf4+SC+ZqiCHhA= 523 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 524 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 525 | golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 526 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= 527 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 528 | golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 529 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 530 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 531 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 532 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 533 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 534 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 535 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 536 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 537 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 538 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 539 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 540 | golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 541 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 542 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 543 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 544 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 545 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 546 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 547 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 548 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 549 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 550 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 551 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 552 | golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 553 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 554 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 555 | golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= 556 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 557 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 558 | golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 559 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 560 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 561 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 562 | golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 563 | golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 564 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 565 | golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 566 | golang.org/x/tools v0.0.0-20201110201400-7099162a900a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 567 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 568 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 569 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 570 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 571 | gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= 572 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 573 | gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= 574 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 575 | google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= 576 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 577 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 578 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 579 | google.golang.org/api v0.9.1-0.20190821000710-329ecc3c9c34/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 580 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 581 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 582 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 583 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 584 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 585 | google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= 586 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 587 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 588 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 589 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 590 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 591 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 592 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 593 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 594 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 595 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 596 | google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 597 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 598 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 599 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 600 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 601 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 602 | google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 603 | google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= 604 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 605 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 606 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 607 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 608 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 609 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 610 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 611 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 612 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 613 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 614 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 615 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 616 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 617 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 618 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 619 | gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 620 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 621 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 622 | gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= 623 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 624 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 625 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 626 | gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 627 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 628 | gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 629 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 630 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 631 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 632 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 633 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 634 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 635 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 636 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 637 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 638 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 639 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 640 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 641 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 642 | k8s.io/api v0.0.0-20181110191121-a33c8200050f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= 643 | k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= 644 | k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= 645 | k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= 646 | k8s.io/apimachinery v0.0.0-20190704094520-6f131bee5e2c/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= 647 | k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= 648 | k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= 649 | k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= 650 | k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= 651 | k8s.io/client-go v0.0.0-20190704095228-386e588352a4/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= 652 | k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= 653 | k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= 654 | k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= 655 | k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= 656 | k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= 657 | k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= 658 | k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= 659 | k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 660 | k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 661 | k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 662 | k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 663 | k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 664 | k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 665 | k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= 666 | k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= 667 | k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= 668 | k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= 669 | k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= 670 | k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= 671 | k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 672 | k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 673 | k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 674 | modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= 675 | modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= 676 | modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= 677 | modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= 678 | modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= 679 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 680 | sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 681 | sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= 682 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 683 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 684 | sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= 685 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 686 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 687 | --------------------------------------------------------------------------------