├── modules ├── worker │ ├── outputs.tf │ ├── templates │ │ └── configuration.hcl.tpl │ ├── README.md │ ├── variables.tf │ └── main.tf ├── boundary │ ├── outputs.tf │ ├── files │ │ └── boundary.service │ ├── main.tf │ ├── README.md │ └── variables.tf └── controller │ ├── templates │ └── configuration.hcl.tpl │ ├── outputs.tf │ ├── README.md │ ├── variables.tf │ └── main.tf ├── versions.tf ├── .pre-commit-config.yaml ├── .tflint.hcl ├── .releaserc ├── outputs.tf ├── .github └── workflows │ └── release.yaml ├── .gitignore ├── LICENSE ├── variables.tf ├── .terraform.lock.hcl ├── main.tf ├── CHANGELOG.md └── README.md /modules/worker/outputs.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | } 6 | } 7 | required_version = ">= 0.13" 8 | } 9 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - hooks: 3 | - id: terraform_docs 4 | repo: "https://github.com/antonbabenko/pre-commit-terraform.git" 5 | rev: v1.51.0 6 | -------------------------------------------------------------------------------- /modules/boundary/outputs.tf: -------------------------------------------------------------------------------- 1 | output "auto_scaling_group_name" { 2 | description = "The name of the controller Auto Scaling group" 3 | value = module.autoscaling.autoscaling_group_name 4 | } 5 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | rule "terraform_documented_outputs" { 2 | enabled = true 3 | } 4 | 5 | rule "terraform_documented_variables" { 6 | enabled = true 7 | } 8 | 9 | rule "terraform_naming_convention" { 10 | enabled = true 11 | format = "snake_case" 12 | } 13 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "branches": "main", 3 | "plugins": [ 4 | "@semantic-release/commit-analyzer", 5 | "@semantic-release/github", 6 | "@semantic-release/release-notes-generator", 7 | "@semantic-release/changelog", 8 | [ 9 | "@semantic-release/git", 10 | { 11 | "assets": [ 12 | "CHANGELOG.md" 13 | ] 14 | } 15 | ] 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /modules/boundary/files/boundary.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Access any system from anywhere based on user identity 3 | Documentation=https://www.boundaryproject.io/docs 4 | 5 | [Service] 6 | ExecStart=/usr/local/bin/boundary server -config /etc/boundary/configuration.hcl 7 | LimitMEMLOCK=infinity 8 | Capabilities=CAP_IPC_LOCK+ep 9 | CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "dns_name" { 2 | description = "The public DNS name of the controller load balancer" 3 | value = module.controllers.dns_name 4 | } 5 | 6 | output "s3command" { 7 | description = "The S3 cp command used to display the contents of the cloud-init-output.log" 8 | 9 | value = format( 10 | "aws s3 cp s3://%s/%s -", 11 | aws_s3_bucket.boundary.id, 12 | data.aws_s3_bucket_objects.cloudinit.keys[0] 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /modules/worker/templates/configuration.hcl.tpl: -------------------------------------------------------------------------------- 1 | disable_mlock = true 2 | 3 | %{ for key in keys ~} 4 | kms "awskms" { 5 | kms_key_id = "${key["key_id"]}" 6 | purpose = "${key["purpose"]}" 7 | } 8 | 9 | %{ endfor ~} 10 | 11 | listener "tcp" { 12 | address = "{{ds.meta_data.local_ipv4}}:9202" 13 | purpose = "proxy" 14 | tls_disable = true 15 | } 16 | 17 | worker { 18 | controllers = ${controllers} 19 | name = "worker-{{v1.local_hostname}}" 20 | public_addr = "{{ds.meta_data.public_ipv4}}" 21 | } 22 | -------------------------------------------------------------------------------- /modules/controller/templates/configuration.hcl.tpl: -------------------------------------------------------------------------------- 1 | controller { 2 | database { 3 | url = "${database_url}" 4 | } 5 | 6 | name = "controller" 7 | } 8 | 9 | disable_mlock = true 10 | 11 | %{ for key in keys ~} 12 | kms "awskms" { 13 | kms_key_id = "${key["key_id"]}" 14 | purpose = "${key["purpose"]}" 15 | } 16 | 17 | %{ endfor ~} 18 | 19 | listener "tcp" { 20 | address = "{{ds.meta_data.local_ipv4}}:9201" 21 | purpose = "cluster" 22 | tls_disable = true 23 | } 24 | 25 | listener "tcp" { 26 | address = "{{ds.meta_data.local_ipv4}}:9200" 27 | purpose = "api" 28 | tls_disable = true 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | release: 3 | name: release 4 | runs-on: ubuntu-latest 5 | steps: 6 | - uses: actions/checkout@v3 7 | - uses: actions/setup-node@v3 8 | with: 9 | node-version: 18 10 | - env: 11 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 12 | name: Run semantic release 13 | run: | 14 | npm install -D @semantic-release/changelog 15 | npm install -D @semantic-release/git 16 | npx semantic-release 17 | name: Release 18 | on: 19 | pull_request: 20 | branches: 21 | - main 22 | push: 23 | branches: 24 | - main 25 | -------------------------------------------------------------------------------- /modules/controller/outputs.tf: -------------------------------------------------------------------------------- 1 | output "bastion_security_group" { 2 | description = "The ID of the bastion security group" 3 | value = one(aws_security_group.bastion[*].id) 4 | } 5 | 6 | output "dns_name" { 7 | description = "The public DNS name of the load balancer" 8 | value = module.alb.lb_dns_name 9 | } 10 | 11 | output "ip_addresses" { 12 | description = "One or more private IPv4 addresses associated with the controllers" 13 | value = data.aws_instances.controllers.private_ips 14 | } 15 | 16 | output "kms_key_id" { 17 | description = "The unique identifier for the worker-auth key" 18 | value = aws_kms_key.auth.key_id 19 | } 20 | 21 | output "security_group_id" { 22 | description = "The ID of the controller security group" 23 | value = aws_security_group.controller.id 24 | } 25 | -------------------------------------------------------------------------------- /.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 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 12 | # .tfvars files are managed as part of configuration and so should be included in 13 | # version control. 14 | # 15 | # example.tfvars 16 | 17 | # Ignore override files as they are usually used to override resources locally and so 18 | # are not checked in 19 | override.tf 20 | override.tf.json 21 | *_override.tf 22 | *_override.tf.json 23 | 24 | # Include override files you do wish to add to version control using negated pattern 25 | # 26 | # !example_override.tf 27 | 28 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 29 | # example: *tfplan* 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 jasonwalsh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /modules/worker/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | | Name | Version | 5 | |------|---------| 6 | | aws | ~> 3.0 | 7 | 8 | ## Providers 9 | 10 | | Name | Version | 11 | |------|---------| 12 | | aws | ~> 3.0 | 13 | 14 | ## Inputs 15 | 16 | | Name | Description | Type | Default | Required | 17 | |------|-------------|------|---------|:--------:| 18 | | bastion\_security\_group | The ID of the bastion security group | `string` | `""` | no | 19 | | boundary\_release | The version of Boundary to install | `string` | `"0.1.0"` | no | 20 | | bucket\_name | The name of the bucket to upload the contents of the
cloud-init-output.log file | `string` | n/a | yes | 21 | | desired\_capacity | The desired capacity is the initial capacity of the Auto Scaling group
at the time of its creation and the capacity it attempts to maintain. | `number` | `3` | no | 22 | | image\_id | The ID of the Amazon Machine Image (AMI) that was assigned during registration | `string` | n/a | yes | 23 | | instance\_type | Specifies the instance type of the EC2 instance | `string` | `"t3.small"` | no | 24 | | ip\_addresses | One or more private IPv4 addresses associated with the controllers | `list(string)` | `[]` | no | 25 | | key\_name | The name of the key pair | `string` | `""` | no | 26 | | kms\_key\_id | The unique identifier for the worker-auth key | `string` | n/a | yes | 27 | | max\_size | The maximum size of the group | `number` | `3` | no | 28 | | min\_size | The minimum size of the group | `number` | `3` | no | 29 | | public\_subnets | List of public subnets | `list(string)` | n/a | yes | 30 | | security\_group\_id | The ID of the controller security group | `string` | n/a | yes | 31 | | tags | One or more tags. You can tag your Auto Scaling group and propagate the tags to
the Amazon EC2 instances it launches. | `map(string)` | `{}` | no | 32 | | vpc\_id | The ID of the VPC | `string` | n/a | yes | 33 | 34 | ## Outputs 35 | 36 | No output. 37 | 38 | 39 | -------------------------------------------------------------------------------- /modules/controller/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | | Name | Version | 5 | |------|---------| 6 | | aws | ~> 3.0 | 7 | 8 | ## Providers 9 | 10 | | Name | Version | 11 | |------|---------| 12 | | aws | ~> 3.0 | 13 | | random | n/a | 14 | 15 | ## Inputs 16 | 17 | | Name | Description | Type | Default | Required | 18 | |------|-------------|------|---------|:--------:| 19 | | boundary\_release | The version of Boundary to install | `string` | `"0.1.0"` | no | 20 | | bucket\_name | The name of the bucket to upload the contents of the
cloud-init-output.log file | `string` | n/a | yes | 21 | | desired\_capacity | The desired capacity is the initial capacity of the Auto Scaling group
at the time of its creation and the capacity it attempts to maintain. | `number` | `3` | no | 22 | | image\_id | The ID of the Amazon Machine Image (AMI) that was assigned during registration | `string` | n/a | yes | 23 | | instance\_type | Specifies the instance type of the EC2 instance | `string` | `"t3.small"` | no | 24 | | key\_name | The name of the key pair | `string` | `""` | no | 25 | | max\_size | The maximum size of the group | `number` | `3` | no | 26 | | min\_size | The minimum size of the group | `number` | `3` | no | 27 | | private\_subnets | List of private subnets | `list(string)` | n/a | yes | 28 | | public\_subnets | List of public subnets | `list(string)` | n/a | yes | 29 | | tags | One or more tags. You can tag your Auto Scaling group and propagate the tags to
the Amazon EC2 instances it launches. | `map(string)` | `{}` | no | 30 | | vpc\_id | The ID of the VPC | `string` | n/a | yes | 31 | 32 | ## Outputs 33 | 34 | | Name | Description | 35 | |------|-------------| 36 | | bastion\_security\_group | The ID of the bastion security group | 37 | | dns\_name | The public DNS name of the load balancer | 38 | | ip\_addresses | One or more private IPv4 addresses associated with the controllers | 39 | | kms\_key\_id | The unique identifier for the worker-auth key | 40 | | security\_group\_id | The ID of the controller security group | 41 | 42 | 43 | -------------------------------------------------------------------------------- /modules/controller/variables.tf: -------------------------------------------------------------------------------- 1 | variable "boundary_release" { 2 | default = "0.1.0" 3 | description = "The version of Boundary to install" 4 | type = string 5 | } 6 | 7 | variable "bucket_name" { 8 | description = < 2 | ## Requirements 3 | 4 | | Name | Version | 5 | |------|---------| 6 | | aws | ~> 3.0 | 7 | 8 | ## Providers 9 | 10 | No provider. 11 | 12 | ## Inputs 13 | 14 | | Name | Description | Type | Default | Required | 15 | |------|-------------|------|---------|:--------:| 16 | | after\_start | Run arbitrary commands after starting the Boundary service | `list(string)` | `[]` | no | 17 | | auto\_scaling\_group\_name | The name of the Auto Scaling group | `string` | n/a | yes | 18 | | before\_start | Run arbitrary commands before starting the Boundary service | `list(string)` | `[]` | no | 19 | | boundary\_release | The version of Boundary to install | `string` | n/a | yes | 20 | | bucket\_name | The name of the bucket to upload the contents of the
cloud-init-output.log file | `string` | n/a | yes | 21 | | desired\_capacity | The desired capacity is the initial capacity of the Auto Scaling group
at the time of its creation and the capacity it attempts to maintain. | `number` | `0` | no | 22 | | iam\_instance\_profile | The name or the Amazon Resource Name (ARN) of the instance profile associated
with the IAM role for the instance | `string` | `""` | no | 23 | | image\_id | The ID of the Amazon Machine Image (AMI) that was assigned during registration | `string` | n/a | yes | 24 | | instance\_type | Specifies the instance type of the EC2 instance | `string` | n/a | yes | 25 | | key\_name | The name of the key pair | `string` | `""` | no | 26 | | max\_size | The maximum size of the group | `number` | n/a | yes | 27 | | min\_size | The minimum size of the group | `number` | n/a | yes | 28 | | security\_groups | A list that contains the security groups to assign to the instances in the Auto
Scaling group | `list(string)` | `[]` | no | 29 | | tags | One or more tags. You can tag your Auto Scaling group and propagate the tags to
the Amazon EC2 instances it launches. | `map(string)` | `{}` | no | 30 | | target\_group\_arns | The Amazon Resource Names (ARN) of the target groups to associate with the Auto
Scaling group | `list(string)` | `[]` | no | 31 | | vpc\_zone\_identifier | A comma-separated list of subnet IDs for your virtual private cloud | `list(string)` | n/a | yes | 32 | | write\_files | Write out arbitrary content to files, optionally setting permissions |
list(object({
content = string
owner = string
path = string
permissions = string
}))
| `[]` | no | 33 | 34 | ## Outputs 35 | 36 | | Name | Description | 37 | |------|-------------| 38 | | auto\_scaling\_group\_name | The name of the controller Auto Scaling group | 39 | 40 | 41 | -------------------------------------------------------------------------------- /.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/hashicorp/aws" { 5 | version = "3.59.0" 6 | constraints = ">= 2.49.0, ~> 3.0, >= 3.38.0, >= 3.40.0, >= 3.44.0" 7 | hashes = [ 8 | "h1:tuHv/1slRRVPlm6a53fWdIV0oqnBe9cOkr0J9as76Cc=", 9 | "zh:0b33154c805071af15839184f3faafeb1549d26a2f1fe721393461790c5ddb46", 10 | "zh:1c5c6793cbec328394c6dda686298d9f6bb7b4c6a39e3dc48dc3035dea9aeda0", 11 | "zh:20b590b9d9f0a18fdc9f0fb18bb2d9d5349b14039899ecf66e4ae5513606405b", 12 | "zh:3e9010dbb0655b5d05e5e98bfe3e1e73cfa5ff6b364dfd73e8eeeb5e1e58c643", 13 | "zh:47a46895d2592fbe7c904107ab6af25abbb17de230852859c06eee95ab282823", 14 | "zh:615745b8c25b111cfe204d52553ea530d84abba7fb8be6b5b00476184407b556", 15 | "zh:701e0f2e5191729601b6d7591e5c3f5d77439125a74116786cca3bc6d7abf0d9", 16 | "zh:7217637b5726bfd09dc9b4f75aef643530e8b673f6de6e06f660a70f4d3170e2", 17 | "zh:8097811557dd5fffcc77e921d3a49dfaa203d4640ac3859a64dcd927122ade8b", 18 | "zh:9a23df54c62dcf74e88aa309700651a6e77e173429ef0307ee15aaa7ff2f47d0", 19 | "zh:e5fa052b9285332a1ebb360ab14676bca88efdaac96cdd809207b23f8e732bb0", 20 | ] 21 | } 22 | 23 | provider "registry.terraform.io/hashicorp/null" { 24 | version = "3.1.0" 25 | constraints = ">= 2.0.0" 26 | hashes = [ 27 | "h1:xhbHC6in3nQryvTQBWKxebi3inG5OCgHgc4fRxL0ymc=", 28 | "zh:02a1675fd8de126a00460942aaae242e65ca3380b5bb192e8773ef3da9073fd2", 29 | "zh:53e30545ff8926a8e30ad30648991ca8b93b6fa496272cd23b26763c8ee84515", 30 | "zh:5f9200bf708913621d0f6514179d89700e9aa3097c77dac730e8ba6e5901d521", 31 | "zh:9ebf4d9704faba06b3ec7242c773c0fbfe12d62db7d00356d4f55385fc69bfb2", 32 | "zh:a6576c81adc70326e4e1c999c04ad9ca37113a6e925aefab4765e5a5198efa7e", 33 | "zh:a8a42d13346347aff6c63a37cda9b2c6aa5cc384a55b2fe6d6adfa390e609c53", 34 | "zh:c797744d08a5307d50210e0454f91ca4d1c7621c68740441cf4579390452321d", 35 | "zh:cecb6a304046df34c11229f20a80b24b1603960b794d68361a67c5efe58e62b8", 36 | "zh:e1371aa1e502000d9974cfaff5be4cfa02f47b17400005a16f14d2ef30dc2a70", 37 | "zh:fc39cc1fe71234a0b0369d5c5c7f876c71b956d23d7d6f518289737a001ba69b", 38 | "zh:fea4227271ebf7d9e2b61b89ce2328c7262acd9fd190e1fd6d15a591abfa848e", 39 | ] 40 | } 41 | 42 | provider "registry.terraform.io/hashicorp/random" { 43 | version = "3.1.0" 44 | constraints = ">= 2.2.0, >= 3.1.0" 45 | hashes = [ 46 | "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=", 47 | "zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc", 48 | "zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626", 49 | "zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff", 50 | "zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2", 51 | "zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992", 52 | "zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427", 53 | "zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc", 54 | "zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f", 55 | "zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b", 56 | "zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7", 57 | "zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a", 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /modules/boundary/variables.tf: -------------------------------------------------------------------------------- 1 | variable "after_start" { 2 | default = [] 3 | description = "Run arbitrary commands after starting the Boundary service" 4 | type = list(string) 5 | } 6 | 7 | variable "auto_scaling_group_name" { 8 | description = "The name of the Auto Scaling group" 9 | type = string 10 | } 11 | 12 | variable "before_start" { 13 | default = [] 14 | description = "Run arbitrary commands before starting the Boundary service" 15 | type = list(string) 16 | } 17 | 18 | variable "boundary_release" { 19 | description = "The version of Boundary to install" 20 | type = string 21 | } 22 | 23 | variable "bucket_name" { 24 | description = < 85 | ## Requirements 86 | 87 | | Name | Version | 88 | |------|---------| 89 | | terraform | ~> 1.0 | 90 | | terraform | >= 0.13 | 91 | 92 | ## Providers 93 | 94 | | Name | Version | 95 | |------|---------| 96 | | aws | n/a | 97 | | random | n/a | 98 | 99 | ## Inputs 100 | 101 | | Name | Description | Type | Default | Required | 102 | |------|-------------|------|---------|:--------:| 103 | | boundary\_release | The version of Boundary to install | `string` | `"0.1.0"` | no | 104 | | cidr\_block | The IPv4 network range for the VPC, in CIDR notation. For example, 10.0.0.0/16. | `string` | `"10.0.0.0/16"` | no | 105 | | controller\_desired\_capacity | The capacity the controller Auto Scaling group attempts to maintain | `number` | `3` | no | 106 | | controller\_instance\_type | Specifies the instance type of the controller EC2 instance | `string` | `"t3.small"` | no | 107 | | controller\_max\_size | The maximum size of the controller group | `number` | `3` | no | 108 | | controller\_min\_size | The minimum size of the controller group | `number` | `3` | no | 109 | | key\_name | The name of the key pair | `string` | `""` | no | 110 | | private\_subnets | List of private subnets | `list(string)` | `[]` | no | 111 | | public\_subnets | List of public subnets | `list(string)` | `[]` | no | 112 | | tags | One or more tags | `map(string)` | `{}` | no | 113 | | vpc\_id | The ID of the VPC | `string` | `""` | no | 114 | | worker\_desired\_capacity | The capacity the worker Auto Scaling group attempts to maintain | `number` | `3` | no | 115 | | worker\_instance\_type | Specifies the instance type of the worker EC2 instance | `string` | `"t3.small"` | no | 116 | | worker\_max\_size | The maximum size of the worker group | `number` | `3` | no | 117 | | worker\_min\_size | The minimum size of the worker group | `number` | `3` | no | 118 | 119 | ## Outputs 120 | 121 | | Name | Description | 122 | |------|-------------| 123 | | dns\_name | The public DNS name of the controller load balancer | 124 | | s3command | The S3 cp command used to display the contents of the cloud-init-output.log | 125 | 126 | 127 | 128 | ## License 129 | 130 | [MIT License](LICENSE) 131 | -------------------------------------------------------------------------------- /modules/controller/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 3.0" 6 | } 7 | } 8 | } 9 | 10 | locals { 11 | configuration = templatefile( 12 | "${path.module}/templates/configuration.hcl.tpl", 13 | { 14 | # Database URL for PostgreSQL 15 | database_url = format( 16 | "postgresql://%s:%s@%s/%s", 17 | module.postgresql.db_instance_username, 18 | module.postgresql.db_instance_password, 19 | module.postgresql.db_instance_endpoint, 20 | module.postgresql.db_instance_name 21 | ) 22 | 23 | keys = [ 24 | { 25 | key_id = aws_kms_key.root.key_id 26 | purpose = "root" 27 | }, 28 | { 29 | key_id = aws_kms_key.auth.key_id 30 | purpose = "worker-auth" 31 | } 32 | ] 33 | } 34 | ) 35 | } 36 | 37 | data "aws_instances" "controllers" { 38 | instance_state_names = ["running"] 39 | 40 | instance_tags = { 41 | "aws:autoscaling:groupName" = module.controllers.auto_scaling_group_name 42 | } 43 | } 44 | 45 | data "aws_s3_bucket" "boundary" { 46 | bucket = var.bucket_name 47 | } 48 | 49 | resource "aws_security_group" "alb" { 50 | egress { 51 | cidr_blocks = ["0.0.0.0/0"] 52 | from_port = 0 53 | protocol = "-1" 54 | to_port = 0 55 | } 56 | 57 | dynamic "ingress" { 58 | for_each = [80, 443] 59 | 60 | content { 61 | cidr_blocks = ["0.0.0.0/0"] 62 | from_port = ingress.value 63 | protocol = "TCP" 64 | to_port = ingress.value 65 | } 66 | } 67 | 68 | name = "Boundary Application Load Balancer" 69 | 70 | tags = merge( 71 | { 72 | Name = "Boundary Application Load Balancer" 73 | }, 74 | var.tags 75 | ) 76 | 77 | vpc_id = var.vpc_id 78 | } 79 | 80 | resource "aws_security_group" "controller" { 81 | name = "Boundary controller" 82 | tags = var.tags 83 | vpc_id = var.vpc_id 84 | } 85 | 86 | resource "aws_security_group_rule" "ssh" { 87 | count = var.key_name != "" ? 1 : 0 88 | 89 | from_port = 22 90 | protocol = "TCP" 91 | security_group_id = aws_security_group.controller.id 92 | source_security_group_id = one(aws_security_group.bastion[*].id) 93 | to_port = 22 94 | type = "ingress" 95 | } 96 | 97 | resource "aws_security_group_rule" "ingress" { 98 | from_port = 9200 99 | protocol = "TCP" 100 | security_group_id = aws_security_group.controller.id 101 | source_security_group_id = aws_security_group.alb.id 102 | to_port = 9200 103 | type = "ingress" 104 | } 105 | 106 | resource "aws_security_group_rule" "egress" { 107 | cidr_blocks = ["0.0.0.0/0"] 108 | from_port = 0 109 | protocol = "-1" 110 | security_group_id = aws_security_group.controller.id 111 | to_port = 0 112 | type = "egress" 113 | } 114 | 115 | resource "aws_security_group" "postgresql" { 116 | ingress { 117 | from_port = 5432 118 | protocol = "TCP" 119 | security_groups = [aws_security_group.controller.id] 120 | to_port = 5432 121 | } 122 | 123 | tags = var.tags 124 | vpc_id = var.vpc_id 125 | } 126 | 127 | module "alb" { 128 | source = "terraform-aws-modules/alb/aws" 129 | version = "~> 6.5" 130 | 131 | http_tcp_listeners = [ 132 | { 133 | port = 80 134 | protocol = "HTTP" 135 | } 136 | ] 137 | 138 | load_balancer_type = "application" 139 | name = "boundary" 140 | security_groups = [aws_security_group.alb.id] 141 | subnets = var.public_subnets 142 | tags = var.tags 143 | 144 | target_groups = [ 145 | { 146 | name = "boundary" 147 | backend_protocol = "HTTP" 148 | backend_port = 9200 149 | } 150 | ] 151 | 152 | vpc_id = var.vpc_id 153 | } 154 | 155 | resource "random_password" "postgresql" { 156 | length = 16 157 | special = false 158 | } 159 | 160 | module "postgresql" { 161 | source = "terraform-aws-modules/rds/aws" 162 | version = "~> 3.4" 163 | 164 | allocated_storage = 5 165 | backup_retention_period = 0 166 | backup_window = "03:00-06:00" 167 | engine = "postgres" 168 | engine_version = var.engine_version 169 | family = "postgres12" 170 | identifier = "boundary" 171 | instance_class = "db.t2.micro" 172 | maintenance_window = "Mon:00:00-Mon:03:00" 173 | major_engine_version = "12" 174 | name = "boundary" 175 | password = random_password.postgresql.result 176 | port = 5432 177 | storage_encrypted = false 178 | subnet_ids = var.private_subnets 179 | tags = var.tags 180 | username = "boundary" 181 | vpc_security_group_ids = [aws_security_group.postgresql.id] 182 | } 183 | 184 | module "controllers" { 185 | source = "../boundary" 186 | 187 | after_start = [ 188 | "grep 'Initial auth information' /var/log/cloud-init-output.log && aws s3 cp /var/log/cloud-init-output.log s3://${var.bucket_name}/{{v1.local_hostname}}/cloud-init-output.log || true" 189 | ] 190 | 191 | auto_scaling_group_name = "BoundaryController" 192 | 193 | # Initialize the DB before starting the service and install the AWS 194 | # CLI. 195 | before_start = [ 196 | "curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip", 197 | "unzip awscliv2.zip", 198 | "./aws/install", 199 | "boundary database init -config /etc/boundary/configuration.hcl -log-format json" 200 | ] 201 | 202 | boundary_release = var.boundary_release 203 | bucket_name = var.bucket_name 204 | desired_capacity = var.desired_capacity 205 | iam_instance_profile = aws_iam_instance_profile.controller.arn 206 | image_id = var.image_id 207 | instance_type = var.instance_type 208 | key_name = var.key_name 209 | max_size = var.max_size 210 | min_size = var.min_size 211 | security_groups = [aws_security_group.controller.id] 212 | tags = var.tags 213 | target_group_arns = module.alb.target_group_arns 214 | vpc_zone_identifier = var.private_subnets 215 | 216 | write_files = [ 217 | { 218 | content = local.configuration 219 | owner = "root:root" 220 | path = "/etc/boundary/configuration.hcl" 221 | permissions = "0644" 222 | } 223 | ] 224 | } 225 | 226 | # https://www.boundaryproject.io/docs/configuration/kms/awskms#authentication 227 | # 228 | # Allows the controllers to invoke the Decrypt, DescribeKey, and Encrypt 229 | # routines for the worker-auth and root keys. 230 | data "aws_iam_policy_document" "controller" { 231 | statement { 232 | actions = [ 233 | "kms:Decrypt", 234 | "kms:DescribeKey", 235 | "kms:Encrypt" 236 | ] 237 | 238 | effect = "Allow" 239 | 240 | resources = [aws_kms_key.auth.arn, aws_kms_key.root.arn] 241 | } 242 | 243 | statement { 244 | actions = [ 245 | "s3:*" 246 | ] 247 | 248 | effect = "Allow" 249 | 250 | resources = [ 251 | "${data.aws_s3_bucket.boundary.arn}/", 252 | "${data.aws_s3_bucket.boundary.arn}/*" 253 | ] 254 | } 255 | } 256 | 257 | data "aws_iam_policy_document" "assume_role_policy" { 258 | statement { 259 | actions = ["sts:AssumeRole"] 260 | 261 | effect = "Allow" 262 | 263 | principals { 264 | identifiers = ["ec2.amazonaws.com"] 265 | type = "Service" 266 | } 267 | } 268 | } 269 | 270 | resource "aws_iam_policy" "controller" { 271 | name = "BoundaryControllerServiceRolePolicy" 272 | policy = data.aws_iam_policy_document.controller.json 273 | } 274 | 275 | resource "aws_iam_role" "controller" { 276 | assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json 277 | name = "ServiceRoleForBoundaryController" 278 | tags = var.tags 279 | } 280 | 281 | resource "aws_iam_role_policy_attachment" "controller" { 282 | policy_arn = aws_iam_policy.controller.arn 283 | role = aws_iam_role.controller.name 284 | } 285 | 286 | resource "aws_iam_instance_profile" "controller" { 287 | role = aws_iam_role.controller.name 288 | } 289 | 290 | # The root key used by controllers 291 | resource "aws_kms_key" "root" { 292 | deletion_window_in_days = 7 293 | key_usage = "ENCRYPT_DECRYPT" 294 | tags = merge(var.tags, { Purpose = "root" }) 295 | } 296 | 297 | # The worker-auth AWS KMS key used by controllers and workers 298 | resource "aws_kms_key" "auth" { 299 | deletion_window_in_days = 7 300 | key_usage = "ENCRYPT_DECRYPT" 301 | tags = merge(var.tags, { Purpose = "worker-auth" }) 302 | } 303 | 304 | resource "aws_security_group" "bastion" { 305 | count = var.key_name != "" ? 1 : 0 306 | 307 | egress { 308 | cidr_blocks = ["0.0.0.0/0"] 309 | from_port = 0 310 | protocol = "-1" 311 | to_port = 0 312 | } 313 | 314 | ingress { 315 | cidr_blocks = ["0.0.0.0/0"] 316 | from_port = 22 317 | protocol = "TCP" 318 | to_port = 22 319 | } 320 | 321 | name = "Boundary Bastion" 322 | tags = var.tags 323 | vpc_id = var.vpc_id 324 | } 325 | 326 | resource "aws_instance" "bastion" { 327 | count = var.key_name != "" ? 1 : 0 328 | 329 | ami = var.image_id 330 | associate_public_ip_address = true 331 | instance_type = "t3.micro" 332 | key_name = var.key_name 333 | subnet_id = var.public_subnets[0] 334 | tags = merge(var.tags, { Name = "Boundary Bastion" }) 335 | vpc_security_group_ids = [one(aws_security_group.bastion[*].id)] 336 | } 337 | --------------------------------------------------------------------------------