Skip to content
Draft
11 changes: 11 additions & 0 deletions hcp-consul-hcp-vault-ca/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.PHONY: init
init:
bash set_region_for_makefile.sh && terraform init && terraform -chdir=./working-environment init

.PHONY: apply
apply:
terraform apply && terraform -chdir=./working-environment apply

.PHONY: destroy
destroy:
terraform -chdir=./working-environment destroy && terraform destroy
32 changes: 32 additions & 0 deletions hcp-consul-hcp-vault-ca/confirm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
export WORKBENCH=$(kubectl get pods -l app=tutorial -o json | jq -r ".items[0].metadata.name")
rc=$(echo $?)

if [ $rc -ne 0 ]
then
echo "Workbench Pod not found. Use kubectl manually, or try again in a moment"
exit 1
fi

echo "Confirming access to Kubernetes resources"
kubectl exec -it "${WORKBENCH}" -- kubectl get pods --all-namespaces >/dev/null
krc=$(echo $?)
sleep 2
echo "Confirming access to HCP Consul"
kubectl exec -it "${WORKBENCH}" -- consul members >/dev/null
crc=$(echo $?)
sleep 2
echo "Confirming access to HCP Vault"
kubectl exec -it "${WORKBENCH}" -- vault status >/dev/null
vrc=$(echo $?)
if [ $krc -ne 0 ] || [ $crc -ne 0 ] || [ $vrc -ne 0 ]
then
echo "Access failed to one or more resources."
echo "Kubernetes returned: $krc"
echo "Consul returned $crc"
echo "Vault returned $vrc"
exit 1
else
echo "Access confirmed!"
exit 0
fi
9 changes: 8 additions & 1 deletion hcp-consul-hcp-vault-ca/data.tf
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# The identity of the AWS User running this terraform project
data "aws_caller_identity" "current" {}
data "aws_caller_identity" "current" {}

data "aws_availability_zones" "current" {
filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}
67 changes: 36 additions & 31 deletions hcp-consul-hcp-vault-ca/main.tf
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
resource "random_string" "identifier" {
length = 6
upper = false
special = false
numeric = true
}

locals {
identifier = random_string.identifier.id
hvn_name = "${var.hcp_hvn_config.name}-${local.identifier}"
peer_id = "${var.hcp_peering_identifier}-${local.identifier}"
vault_cluster = "${var.hcp_vault_cluster_name}-${local.identifier}"
consul_datacenter = "${var.hcp_consul_datacenter_name}-${local.identifier}"
eks_name = "${var.cluster_and_vpc_info.name}-${local.identifier}"
policy_name = "${var.cluster_and_vpc_info.policy_name}-${local.identifier}"
}

# Builds the base VPC for the AWS EKS Cluster
module "aws_vpc" {
# Full URL due to this issue: https://github.com/VladRassokhin/intellij-hcl/issues/365
source = "registry.terraform.io/terraform-aws-modules/vpc/aws"
version = "3.11.5"
name = var.cluster_and_vpc_info.vpc_name
name = local.identifier
cidr = var.aws_cidr_block.allocation
azs = var.availability_zones
azs = data.aws_availability_zones.current.names
private_subnets = var.aws_cidr_block.subnets.private
public_subnets = var.aws_cidr_block.subnets.public
enable_nat_gateway = true
enable_vpn_gateway = false
# internal-lb: Permits internal Load Balancer creation when a LoadBalancer type is passed.
private_subnet_tags = {
"kubernetes.io/cluster/${var.cluster_and_vpc_info.name}" = "shared"
"kubernetes.io/role/internal-elb" = "1"
"kubernetes.io/cluster/${local.eks_name}" = "shared"
"kubernetes.io/role/internal-elb" = "1"
}
#elb: Permits Elastic Load Balancer creation when a LoadBalancer type is passed.
public_subnet_tags = {
"kubernetes.io/cluster/${var.cluster_and_vpc_info.name}" = "shared"
"kubernetes.io/role/elb" = "1"
"kubernetes.io/cluster/${local.eks_name}" = "shared"
"kubernetes.io/role/elb" = "1"
}

tags = {
Terraform = "true"
Environment = var.cluster_and_vpc_info.stage
}
}

# Creates required AWS Services to complete the peering relationship. If needed later
Expand All @@ -41,7 +54,7 @@ module "hcp_networking_primitives" {
source = "./modules/hcp_networking_primitives"
cloud_provider = var.cloud_provider
hcp_region = var.hcp_region
hvn_name = var.hcp_hvn_config.name
hvn_name = local.hvn_name
cidr_block = var.hcp_hvn_config.allocation
}

Expand All @@ -56,7 +69,7 @@ module "hcp_networking" {
aws_vpc_cidr_block = var.aws_cidr_block.allocation
hvn_link = module.hcp_networking_primitives.hvn_link
hvn_name = module.hcp_networking_primitives.hcp_vpn_id
hvn_peering_identifier = var.hcp_peering_identifier
hvn_peering_identifier = local.peer_id
hcp_hvn_cidr_block = var.hcp_hvn_config.allocation
public_route_table_ids = module.aws_vpc.public_route_table_ids
private_route_table_ids = module.aws_vpc.private_route_table_ids
Expand All @@ -66,8 +79,8 @@ module "hcp_networking" {
module "hcp_applications" {
source = "./modules/hcp_applications"
hvn_id = module.hcp_networking_primitives.hcp_vpn_id
consul_cluster_datacenter = var.hcp_consul_datacenter_name
vault_cluster_name = var.hcp_vault_cluster_name
consul_cluster_datacenter = local.consul_datacenter
vault_cluster_name = local.vault_cluster
hcp_consul_tier = var.hcp_hvn_config.consul_tier
hcp_vault_tier = var.hcp_hvn_config.vault_tier
}
Expand All @@ -77,11 +90,9 @@ module "eks" {
# Full URL due to this issue: https://github.com/VladRassokhin/intellij-hcl/issues/365
source = "registry.terraform.io/terraform-aws-modules/eks/aws"
version = "18.9.0"
cluster_name = var.cluster_and_vpc_info.name
cluster_name = local.eks_name
cluster_endpoint_private_access = true
cluster_endpoint_public_access = true


cluster_addons = {
coredns = {
resolve_conflicts = "OVERWRITE"
Expand Down Expand Up @@ -117,35 +128,29 @@ module "eks" {
tags = {
Environment = var.cluster_and_vpc_info.stage
}

}

# Update local environment's kubeconfig file.
resource "null_resource" "update_kubeconfig" {

provisioner "local-exec" {
# Create empty kubeconfig if it doesn't exist. If it does exist, touch does nothing, but back up the config in either case and use a kubeconfig that is unique for this tutorial. Is deleted during terraform destroy
command = "mv ~/.kube/config ~/.kube/config.bkp && aws eks --region ${var.cluster_and_vpc_info.region} update-kubeconfig --name ${module.eks.cluster_id} --alias ${var.cluster_and_vpc_info.name}"
command = "aws eks --region ${var.region} update-kubeconfig --name ${module.eks.cluster_id} --alias ${module.eks.cluster_id}"
}
depends_on = [module.eks]
}

# This module's resources only run when `terraform destroy` is invoked by the user. A "start_cleanup" variable
# is used to make sure cleanup scripts are not run during a follow up terraform apply, and only during terraform destroy.
# This is passed as TF_VAR_start_cleanup=true to the main project by the reader at the end of the tutorial:
# export TF_VAR_run_cleanup=true; terraform destroy -auto-approve
module "cleanup" {
source = "./modules/cleanup"
vpc_id = module.aws_vpc.vpc_id
region = var.region
cluster_name = var.cluster_and_vpc_info.name
cluster_name = local.eks_name
start_cleanup = var.run_cleanup
}

# This module does all the OIDC magic for ServiceAccount -> IAM Role mapping
module "iam_role_for_service_accounts" {
source = "registry.terraform.io/terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
role_name = lower(var.cluster_and_vpc_info.name)
role_name = local.eks_name
version = "4.14.0"

oidc_providers = {
Expand All @@ -162,7 +167,7 @@ module "eks_iam" {
source = "./modules/iam"
cluster_arn = module.eks.cluster_arn
description = var.cluster_and_vpc_info.policy_description
policy_name = var.cluster_and_vpc_info.policy_name
policy_name = local.policy_name
role_name = module.iam_role_for_service_accounts.iam_role_name
}

Expand All @@ -186,12 +191,12 @@ consul_secret_id ="${module.hcp_applications.consul_root_token_secret_id}"
vault_addr="${module.hcp_applications.vault_cluster_host}"
vault_namespace="${var.hcp_vault_default_namespace}"
vault_token="${module.hcp_applications.vault_admin_token}"
kube_context="${var.cluster_and_vpc_info.name}"
kube_context="${local.eks_name}"
role_arn="${module.iam_role_for_service_accounts.iam_role_arn}"
profile_name="${var.profile_name}"
cluster_service_account_name="${var.kube_service_account_name}"
cluster_name="${var.cluster_and_vpc_info.name}"
cluster_region="${var.cluster_and_vpc_info.region}"
cluster_name="${local.eks_name}"
cluster_region="${var.region}"
consul_datacenter="${module.hcp_applications.consul_datacenter}"
CONFIGURATION
}

5 changes: 5 additions & 0 deletions hcp-consul-hcp-vault-ca/modules/hcp_applications/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ output "consul_cluster_host" {
value = hcp_consul_cluster.server.consul_private_endpoint_url
}

# Consul datacenter name
output "consul_datacenter" {
value = hcp_consul_cluster.server.datacenter
}

# The Consul config file to setup the working environment
output "consul_config_file" {
value = hcp_consul_cluster.server.consul_config_file
Expand Down
28 changes: 28 additions & 0 deletions hcp-consul-hcp-vault-ca/modules/kubernetes/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ resource "kubernetes_config_map" "aws_profile_config" {
}
}

resource "kubernetes_config_map" "consul_values" {
metadata {
name = "consul-values.yaml"
}
data = {
"consul-values.yaml" = templatefile("${path.module}/template_scripts/consul-values.tftpl", {
vault_addr = var.vault_addr
# remove "https://" from the URL for correct format in helm chart
hcp_consul_addr = substr(var.consul_http_addr, 8, -1)
kube_control_plane = var.consul_k8s_api_aws,
datacenter = var.consul_datacenter
})
}
}

# Create a service account for this pod
resource "kubernetes_service_account" "tutorial" {
metadata {
Expand Down Expand Up @@ -125,6 +140,13 @@ resource "kubernetes_deployment" "workingEnvironment" {
default_mode = var.aws_creds_options.file_permissions
}
}
volume {
name = "consul-values"
config_map {
name = "consul-values.yaml"
default_mode = "0755"
}
}
volume {
name = var.aws_profile_config_options.volume_name
config_map {
Expand Down Expand Up @@ -192,6 +214,12 @@ resource "kubernetes_deployment" "workingEnvironment" {
sub_path = var.aws_creds_options.config_map_filename
read_only = true
}
volume_mount {
mount_path = "/consul-values.yaml"
name = "consul-values"
sub_path = "consul-values.yaml"
read_only = false
}
volume_mount {
mount_path = var.aws_profile_config_options.mount_path
name = var.aws_profile_config_options.volume_name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
global:
name: consul
enabled: false
datacenter: ${datacenter}
image: hashicorp/consul-enterprise:1.11.4-ent
enableConsulNamespaces: true
acls:
manageSystemACLs: true
bootstrapToken:
secretName: consul-bootstrap-token
secretKey: token
gossipEncryption:
secretName: consul-gossip-key
secretKey: key
tls:
enabled: true
enableAutoEncrypt: true
caCert:
secretName: consul-ca-cert
secretKey: tls.crt
externalServers:
enabled: true
hosts:
- ${hcp_consul_addr}
httpsPort: 443
useSystemRoots: true
k8sAuthMethodHost: ${kube_control_plane}
client:
enabled: true
grpc: true
join:
- ${hcp_consul_addr}
connectInject:
enabled: true
envoyExtraArgs: "--component-log-level upstream:debug,http:debug,router:debug,config:debug"
aclBindingRuleSelector: ''
consulNamespaces:
mirroringK8S: true
transparentProxy:
defaultEnabled: false
controller:
enabled: true
secretsBackend:
vault:
enabled: true
# https://www.consul.io/docs/k8s/helm#v-global-secretsbackend-vault-consulclientrole
consulClientRole: consul-consul-client
consulCARole: consul-consul-client
# https://www.consul.io/docs/k8s/helm#v-global-secretsbackend-vault-connectca
connectCA:
address: ${vault_addr}
rootPKIPath: /connect_root
intermediatePKIPath: /connect_inter
additionalConfig: |
{
"connect": [{
"ca_config": [{
"leaf_cert_ttl": "72h",
"intermediate_cert_ttl": "8760h",
"rotation_period": "2160h",
"namespace": "admin"
}]
}]
}
5 changes: 5 additions & 0 deletions hcp-consul-hcp-vault-ca/modules/kubernetes/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,8 @@ variable "kube_context" {
description = "The name of the kube context to set in the config file for kubectl"
}

variable "consul_datacenter" {
type = string
description = "The name of the Consul datacenter"
}

3 changes: 0 additions & 3 deletions hcp-consul-hcp-vault-ca/provider.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ terraform {

provider "aws" {
region = var.region
default_tags {
tags = var.default_tags
}
}

provider "hcp" {}
Expand Down
12 changes: 12 additions & 0 deletions hcp-consul-hcp-vault-ca/set_region_for_makefile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

TF_VAR_region=$(read -p "Enter the AWS Region to use for this project (e.g. us-east-1) > ")

if [ ! $TF_VAR_region ]; then
# Set val if user skips entering any intput, and default to us-east-1
TF_VAR_region="us-east-1"
echo "region=\"${TF_VAR_region}\"" > terraform.tfvars
echo "hcp_region=\"${TF_VAR_region}\"" >> terraform.tfvars
fi

exit 0
Loading