Skip to content

Commit 90923b9

Browse files
committed
initial commit
0 parents  commit 90923b9

13 files changed

+942
-0
lines changed

buildspec_terraform_apply.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: 0.2
2+
3+
phases:
4+
install:
5+
runtime-versions:
6+
python: 3.7
7+
commands:
8+
- tf_version=$TERRAFORM_VERSION
9+
- wget https://releases.hashicorp.com/terraform/"$TERRAFORM_VERSION"/terraform_"$TERRAFORM_VERSION"_linux_amd64.zip
10+
- unzip terraform_"$TERRAFORM_VERSION"_linux_amd64.zip
11+
- mv terraform /usr/local/bin/
12+
build:
13+
commands:
14+
- terraform --version
15+
- terraform init -input=false
16+
- terraform apply -auto-approve -input=false

buildspec_terraform_plan.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
version: 0.2
2+
3+
phases:
4+
install:
5+
runtime-versions:
6+
python: 3.7
7+
commands:
8+
- tf_version=$TERRAFORM_VERSION
9+
- wget https://releases.hashicorp.com/terraform/"$TERRAFORM_VERSION"/terraform_"$TERRAFORM_VERSION"_linux_amd64.zip
10+
- unzip terraform_"$TERRAFORM_VERSION"_linux_amd64.zip
11+
- mv terraform /usr/local/bin/
12+
build:
13+
commands:
14+
- terraform --version
15+
- terraform init -input=false
16+
- terraform validate
17+
- terraform plan -lock=false -input=false

main.tf

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Require TF version to be same as or greater than 0.12.16
2+
terraform {
3+
required_version = ">=0.12.16"
4+
backend "s3" {
5+
bucket = "kyler-codebuild-demo-terraform-tfstate"
6+
key = "terraform.tfstate"
7+
region = "us-east-1"
8+
dynamodb_table = "codebuild-dynamodb-terraform-locking"
9+
encrypt = true
10+
}
11+
}
12+
13+
# Download any stable version in AWS provider of 2.36.0 or higher in 2.36 train
14+
provider "aws" {
15+
region = "us-east-1"
16+
version = "~> 2.36.0"
17+
assume_role {
18+
# Remember to update this account ID to yours
19+
role_arn = "arn:aws:iam::718626770228:role/TerraformAssumedIamRole"
20+
session_name = "terraform"
21+
}
22+
}
23+
24+
25+
## Step 1: Build an IAM user with administrative rights
26+
# Export the access key and secret access key into global bash variables. The commands will look like this:
27+
# export AWS_ACCESS_KEY_ID="AKIA2OULU2K4324HLYFNU"
28+
# export AWS_SECRET_ACCESS_KEY="b8ma12345678901234567890toWCOjo"
29+
30+
31+
## Step 2: Build an S3 bucket and DynamoDB for Terraform state and locking
32+
module "bootstrap" {
33+
source = "./modules/bootstrap"
34+
s3_tfstate_bucket = "kyler-codebuild-demo-terraform-tfstate"
35+
s3_logging_bucket_name = "kyler-codebuild-demo-logging-bucket"
36+
dynamo_db_table_name = "codebuild-dynamodb-terraform-locking"
37+
codebuild_iam_role_name = "CodeBuildIamRole"
38+
codebuild_iam_role_policy_name = "CodeBuildIamRolePolicy"
39+
terraform_codecommit_repo_arn = module.codecommit.terraform_codecommit_repo_arn
40+
tf_codepipeline_artifact_bucket_arn = module.codepipeline.tf_codepipeline_artifact_bucket_arn
41+
}
42+
43+
## Step 3: Build a CodeCommit git repo
44+
module "codecommit" {
45+
source = "./modules/codecommit"
46+
repository_name = "CodeCommitTerraform"
47+
}
48+
49+
50+
## Step 4: Build CodeBuild projects for Terraform Plan and Terraform Apply
51+
module "codebuild" {
52+
source = "./modules/codebuild"
53+
codebuild_project_terraform_plan_name = "TerraformPlan"
54+
codebuild_project_terraform_apply_name = "TerraformApply"
55+
s3_logging_bucket_id = module.bootstrap.s3_logging_bucket_id
56+
codebuild_iam_role_arn = module.bootstrap.codebuild_iam_role_arn
57+
s3_logging_bucket = module.bootstrap.s3_logging_bucket
58+
}
59+
60+
61+
## Step 5: Build a CodePipeline
62+
module "codepipeline" {
63+
source = "./modules/codepipeline"
64+
tf_codepipeline_name = "TerraformCodePipeline"
65+
tf_codepipeline_artifact_bucket_name = "kyler-codebuild-demo-artifact-bucket-name"
66+
tf_codepipeline_role_name = "TerraformCodePipelineIamRole"
67+
tf_codepipeline_role_policy_name = "TerraformCodePipelineIamRolePolicy"
68+
terraform_codecommit_repo_name = module.codecommit.terraform_codecommit_repo_name
69+
codebuild_terraform_plan_name = module.codebuild.codebuild_terraform_plan_name
70+
codebuild_terraform_apply_name = module.codebuild.codebuild_terraform_apply_name
71+
}

modules/bootstrap/bootstrap.tf

+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
##
2+
# Module to build the Azure DevOps "seed" configuration
3+
##
4+
5+
# Build an S3 bucket to store TF state
6+
resource "aws_s3_bucket" "state_bucket" {
7+
bucket = var.s3_tfstate_bucket
8+
9+
# Tells AWS to encrypt the S3 bucket at rest by default
10+
server_side_encryption_configuration {
11+
rule {
12+
apply_server_side_encryption_by_default {
13+
sse_algorithm = "AES256"
14+
}
15+
}
16+
}
17+
18+
# Prevents Terraform from destroying or replacing this object - a great safety mechanism
19+
lifecycle {
20+
prevent_destroy = true
21+
}
22+
23+
# Tells AWS to keep a version history of the state file
24+
versioning {
25+
enabled = true
26+
}
27+
28+
tags = {
29+
Terraform = "true"
30+
}
31+
}
32+
33+
# Build a DynamoDB to use for terraform state locking
34+
resource "aws_dynamodb_table" "tf_lock_state" {
35+
name = var.dynamo_db_table_name
36+
37+
# Pay per request is cheaper for low-i/o applications, like our TF lock state
38+
billing_mode = "PAY_PER_REQUEST"
39+
40+
# Hash key is required, and must be an attribute
41+
hash_key = "LockID"
42+
43+
# Attribute LockID is required for TF to use this table for lock state
44+
attribute {
45+
name = "LockID"
46+
type = "S"
47+
}
48+
49+
tags = {
50+
Name = var.dynamo_db_table_name
51+
Terraform = "true"
52+
}
53+
}
54+
55+
56+
# Build an AWS S3 bucket for logging
57+
resource "aws_s3_bucket" "s3_logging_bucket" {
58+
bucket = var.s3_logging_bucket_name
59+
acl = "private"
60+
61+
server_side_encryption_configuration {
62+
rule {
63+
apply_server_side_encryption_by_default {
64+
sse_algorithm = "AES256"
65+
}
66+
}
67+
}
68+
}
69+
70+
# Output name of S3 logging bucket back to main.tf
71+
output "s3_logging_bucket_id" {
72+
value = aws_s3_bucket.s3_logging_bucket.id
73+
}
74+
output "s3_logging_bucket" {
75+
value = aws_s3_bucket.s3_logging_bucket.bucket
76+
}
77+
78+
# Create an IAM role for CodeBuild to assume
79+
resource "aws_iam_role" "codebuild_iam_role" {
80+
name = var.codebuild_iam_role_name
81+
82+
assume_role_policy = <<EOF
83+
{
84+
"Version": "2012-10-17",
85+
"Statement": [
86+
{
87+
"Effect": "Allow",
88+
"Principal": {
89+
"Service": "codebuild.amazonaws.com"
90+
},
91+
"Action": "sts:AssumeRole"
92+
}
93+
]
94+
}
95+
EOF
96+
}
97+
98+
# Output the CodeBuild IAM role
99+
output "codebuild_iam_role_arn" {
100+
value = aws_iam_role.codebuild_iam_role.arn
101+
}
102+
103+
104+
# Create an IAM role policy for CodeBuild to use implicitly
105+
resource "aws_iam_role_policy" "codebuild_iam_role_policy" {
106+
name = var.codebuild_iam_role_policy_name
107+
role = aws_iam_role.codebuild_iam_role.name
108+
109+
policy = <<POLICY
110+
{
111+
"Version": "2012-10-17",
112+
"Statement": [
113+
{
114+
"Effect": "Allow",
115+
"Resource": [
116+
"*"
117+
],
118+
"Action": [
119+
"logs:CreateLogGroup",
120+
"logs:CreateLogStream",
121+
"logs:PutLogEvents"
122+
]
123+
},
124+
{
125+
"Effect": "Allow",
126+
"Action": [
127+
"s3:*"
128+
],
129+
"Resource": [
130+
"${aws_s3_bucket.s3_logging_bucket.arn}",
131+
"${aws_s3_bucket.s3_logging_bucket.arn}/*",
132+
"${aws_s3_bucket.state_bucket.arn}",
133+
"${aws_s3_bucket.state_bucket.arn}/*",
134+
"arn:aws:s3:::codepipeline-us-east-1*",
135+
"arn:aws:s3:::codepipeline-us-east-1*/*",
136+
"${var.tf_codepipeline_artifact_bucket_arn}",
137+
"${var.tf_codepipeline_artifact_bucket_arn}/*"
138+
]
139+
},
140+
{
141+
"Effect": "Allow",
142+
"Action": [
143+
"dynamodb:*"
144+
],
145+
"Resource": "${aws_dynamodb_table.tf_lock_state.arn}"
146+
},
147+
{
148+
"Effect": "Allow",
149+
"Action": [
150+
"codecommit:BatchGet*",
151+
"codecommit:BatchDescribe*",
152+
"codecommit:Describe*",
153+
"codecommit:EvaluatePullRequestApprovalRules",
154+
"codecommit:Get*",
155+
"codecommit:List*",
156+
"codecommit:GitPull"
157+
],
158+
"Resource": "${var.terraform_codecommit_repo_arn}"
159+
},
160+
{
161+
"Effect": "Allow",
162+
"Action": [
163+
"iam:Get*",
164+
"iam:List*"
165+
],
166+
"Resource": "${aws_iam_role.codebuild_iam_role.arn}"
167+
},
168+
{
169+
"Effect": "Allow",
170+
"Action": "sts:AssumeRole",
171+
"Resource": "${aws_iam_role.codebuild_iam_role.arn}"
172+
}
173+
]
174+
}
175+
POLICY
176+
}
177+
178+
179+
# Create IAM role for Terraform builder to assume
180+
resource "aws_iam_role" "tf_iam_assumed_role" {
181+
name = "TerraformAssumedIamRole"
182+
183+
assume_role_policy = <<EOF
184+
{
185+
"Version": "2012-10-17",
186+
"Statement": [
187+
{
188+
"Effect": "Allow",
189+
"Principal": {
190+
"AWS": "${aws_iam_role.codebuild_iam_role.arn}"
191+
},
192+
"Action": "sts:AssumeRole"
193+
}
194+
]
195+
}
196+
EOF
197+
198+
lifecycle {
199+
prevent_destroy = true
200+
}
201+
202+
tags = {
203+
Terraform = "true"
204+
}
205+
}
206+
207+
208+
# Create broad IAM policy Terraform to use to build, modify resources
209+
resource "aws_iam_policy" "tf_iam_assumed_policy" {
210+
name = "TerraformAssumedIamPolicy"
211+
212+
policy = <<EOF
213+
{
214+
"Version": "2012-10-17",
215+
"Statement": [
216+
{
217+
"Sid": "AllowAllPermissions",
218+
"Effect": "Allow",
219+
"Action": [
220+
"*"
221+
],
222+
"Resource": "*"
223+
}
224+
]
225+
}
226+
EOF
227+
228+
lifecycle {
229+
prevent_destroy = true
230+
}
231+
}
232+
233+
# Attach IAM assume role to policy
234+
resource "aws_iam_role_policy_attachment" "tf_iam_attach_assumed_role_to_permissions_policy" {
235+
role = aws_iam_role.tf_iam_assumed_role.name
236+
policy_arn = aws_iam_policy.tf_iam_assumed_policy.arn
237+
238+
lifecycle {
239+
prevent_destroy = true
240+
}
241+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
##
2+
# Define variables for Azure DevOps Seed Module
3+
##
4+
5+
variable "s3_tfstate_bucket" {
6+
description = "Name of the S3 bucket used for Terraform state storage"
7+
}
8+
variable "s3_logging_bucket_name" {
9+
description = "Name of S3 bucket to use for access logging"
10+
}
11+
variable "dynamo_db_table_name" {
12+
description = "Name of DynamoDB table used for Terraform locking"
13+
}
14+
variable "codebuild_iam_role_name" {
15+
description = "Name for IAM Role utilized by CodeBuild"
16+
}
17+
variable "codebuild_iam_role_policy_name" {
18+
description = "Name for IAM policy used by CodeBuild"
19+
}
20+
variable "terraform_codecommit_repo_arn" {
21+
description = "Terraform CodeCommit git repo ARN"
22+
}
23+
variable "tf_codepipeline_artifact_bucket_arn" {
24+
description = "Codepipeline artifact bucket ARN"
25+
}

0 commit comments

Comments
 (0)