mirror of
https://github.com/kerberos-io/deployment.git
synced 2026-08-23 15:18:32 +00:00
feat(aws): add Terraform module for Amazon EKS and DocumentDB setup
This commit is contained in:
@@ -1 +1,57 @@
|
||||
# Amazon DocumentDB
|
||||
|
||||
[Amazon DocumentDB](https://aws.amazon.com/documentdb/) is a managed, MongoDB
|
||||
compatible database. It can be used as the metadata store for Kerberos Hub
|
||||
instead of a self-hosted MongoDB.
|
||||
|
||||
## Things to know
|
||||
|
||||
- **Not reachable from outside its VPC.** DocumentDB has no public endpoint, so
|
||||
the Kerberos Hub services must run inside (or be peered with) the same VPC.
|
||||
- **TLS is enabled by default.** Clients must trust the Amazon RDS certificate
|
||||
authority bundle:
|
||||
`https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem`.
|
||||
- **Not every MongoDB feature is available.** Retryable writes, the MongoDB
|
||||
Stable API, geospatial queries/indexes and complex `$lookup` pipelines are
|
||||
unsupported. Set `mongodb.flavor: "documentdb"` and
|
||||
`mongodb.retryWrites: "false"` in the hub chart so those code paths are
|
||||
disabled.
|
||||
|
||||
## Provisioning
|
||||
|
||||
The [`amazon-eks-documentdb`](../amazon-eks-documentdb/README.md) Terraform
|
||||
stack creates a VPC, an EKS cluster and a DocumentDB cluster with TLS enforced,
|
||||
and outputs a ready to paste `mongodb` values block for the hub helm chart.
|
||||
|
||||
## Connecting Kerberos Hub
|
||||
|
||||
Configure the database through `mongodb.uri` (not `mongodb.host`) and point the
|
||||
chart at the CA bundle:
|
||||
|
||||
```bash
|
||||
curl -O https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
|
||||
kubectl create secret generic mongodb-ca --from-file=global-bundle.pem -n kerberos-hub
|
||||
```
|
||||
|
||||
```yaml
|
||||
mongodb:
|
||||
flavor: "documentdb"
|
||||
retryWrites: "false"
|
||||
uri: "mongodb://<user>:<password>@<cluster>.docdb.amazonaws.com:27017/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
|
||||
adminDatabase: "admin"
|
||||
authenticationMechanism: "SCRAM-SHA-1"
|
||||
tls:
|
||||
enabled: true
|
||||
existingSecret: "mongodb-ca"
|
||||
caFileName: "global-bundle.pem"
|
||||
mountPath: "/certs"
|
||||
```
|
||||
|
||||
The chart mounts the bundle read-only into every workload that talks to
|
||||
MongoDB and appends `tls=true&tlsCAFile=/certs/global-bundle.pem` to the
|
||||
connection string.
|
||||
|
||||
## Related
|
||||
|
||||
- [`../amazon-eks-documentdb`](../amazon-eks-documentdb/README.md) — Terraform for EKS + DocumentDB
|
||||
- [`../../overlays/documentdb`](../../overlays/documentdb) — Kustomize overlay using DocumentDB
|
||||
|
||||
12
modules/amazon-eks-documentdb/.gitignore
vendored
Normal file
12
modules/amazon-eks-documentdb/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
*.tfplan
|
||||
crash.log
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
terraform.tfvars
|
||||
*.auto.tfvars
|
||||
236
modules/amazon-eks-documentdb/README.md
Normal file
236
modules/amazon-eks-documentdb/README.md
Normal file
@@ -0,0 +1,236 @@
|
||||
# Amazon EKS + DocumentDB (Terraform)
|
||||
|
||||
Terraform stack that creates a **basic Kubernetes cluster (EKS) and a managed
|
||||
MongoDB-compatible database (Amazon DocumentDB) on AWS**, wired together so
|
||||
Kerberos Hub can be installed on it straight away.
|
||||
|
||||
It is primarily meant as a **reproducible test environment** for the DocumentDB
|
||||
support in the [`hub` helm chart](https://github.com/kerberos-io/helm-charts),
|
||||
in particular the `mongodb.tls.*` values that mount the Amazon RDS certificate
|
||||
authority bundle. It is deliberately small and cheap, not a hardened production
|
||||
landing zone.
|
||||
|
||||
## What it creates
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph VPC["VPC (10.20.0.0/16)"]
|
||||
subgraph Public["Public subnets"]
|
||||
NAT[NAT gateway]
|
||||
LB[Load balancers]
|
||||
end
|
||||
subgraph Private["Private subnets"]
|
||||
NODES[EKS managed node group]
|
||||
DOCDB[(DocumentDB cluster<br/>TLS enforced)]
|
||||
end
|
||||
end
|
||||
EKSCP[EKS control plane] --- NODES
|
||||
NODES -- "27017 / TLS" --> DOCDB
|
||||
NODES --> NAT
|
||||
```
|
||||
|
||||
| Component | Details |
|
||||
| --------- | ------- |
|
||||
| VPC | Public + private subnets across 3 availability zones, internet gateway, NAT gateway |
|
||||
| EKS | Managed control plane, one managed node group, `coredns`, `kube-proxy`, `vpc-cni`, `eks-pod-identity-agent` and `aws-ebs-csi-driver` add-ons (IRSA role included) |
|
||||
| DocumentDB | Cluster + instances in the private subnets, encryption **at rest** (KMS) and **in transit** (`tls=enabled`), subnet group, cluster parameter group |
|
||||
| Security | A dedicated security group that only allows port `27017` from the EKS worker node security group (plus any extra CIDRs you pass in) |
|
||||
|
||||
> [!IMPORTANT]
|
||||
> DocumentDB has **no public endpoint**. It can only be reached from inside the
|
||||
> VPC, which is why the workloads that talk to it must run on this cluster (or
|
||||
> you must tunnel through a bastion host / VPN).
|
||||
|
||||
> [!WARNING]
|
||||
> This stack costs money while it exists (EKS control plane, NAT gateway, EC2
|
||||
> nodes, DocumentDB instances and storage). Run `terraform destroy` when you are
|
||||
> done.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Terraform](https://developer.hashicorp.com/terraform/downloads) >= 1.5
|
||||
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) v2, authenticated with permissions to create VPC, EKS, IAM and DocumentDB resources
|
||||
- `kubectl` and `helm`
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd deployment/modules/amazon-eks-documentdb
|
||||
|
||||
cp terraform.tfvars.example terraform.tfvars
|
||||
$EDITOR terraform.tfvars
|
||||
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
Creating the cluster and the database takes a while (EKS and DocumentDB are
|
||||
both slow to provision).
|
||||
|
||||
State is kept locally by default. For anything shared, add a backend, for
|
||||
example:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "my-terraform-state"
|
||||
key = "kerberos-hub/eks-documentdb.tfstate"
|
||||
region = "eu-west-1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Connect kubectl
|
||||
|
||||
```bash
|
||||
$(terraform output -raw update_kubeconfig_command)
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
## Installing Kerberos Hub against DocumentDB
|
||||
|
||||
### 1. Create the certificate authority secret
|
||||
|
||||
DocumentDB presents a certificate signed by the Amazon RDS certificate
|
||||
authority, so every client needs the bundle:
|
||||
|
||||
```bash
|
||||
kubectl create namespace kerberos-hub
|
||||
|
||||
curl -O https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
|
||||
kubectl create secret generic mongodb-ca \
|
||||
--from-file=global-bundle.pem \
|
||||
-n kerberos-hub
|
||||
```
|
||||
|
||||
### 2. Generate the values
|
||||
|
||||
```bash
|
||||
terraform output -raw hub_values_snippet > hub-documentdb-values.yaml
|
||||
```
|
||||
|
||||
Which produces something like:
|
||||
|
||||
```yaml
|
||||
mongodb:
|
||||
flavor: "documentdb"
|
||||
retryWrites: "false"
|
||||
uri: "mongodb://kerberos:...@kerberos-hub-docdb.cluster-xxxx.eu-west-1.docdb.amazonaws.com:27017/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
|
||||
adminDatabase: "admin"
|
||||
authenticationMechanism: "SCRAM-SHA-1"
|
||||
tls:
|
||||
enabled: true
|
||||
existingSecret: "mongodb-ca"
|
||||
caFileName: "global-bundle.pem"
|
||||
mountPath: "/certs"
|
||||
```
|
||||
|
||||
The chart mounts the bundle into every workload that talks to MongoDB, appends
|
||||
`tls=true&tlsCAFile=/certs/global-bundle.pem` to the URI, and exposes
|
||||
`MONGODB_TLS`, `MONGODB_TLS_CA_FILE` and `MONGODB_TLS_INSECURE_SKIP_VERIFY`
|
||||
through the `mongodb-config` ConfigMap.
|
||||
|
||||
> [!NOTE]
|
||||
> With DocumentDB you must configure the database through `mongodb.uri`, not
|
||||
> through `mongodb.host` / `mongodb.username` / `mongodb.password`, so that the
|
||||
> TLS parameters end up in the connection string that every service uses.
|
||||
|
||||
### 3. Install the chart
|
||||
|
||||
```bash
|
||||
helm repo add kerberos https://charts.kerberos.io
|
||||
helm install hub kerberos/hub \
|
||||
-n kerberos-hub \
|
||||
-f your-hub-values.yaml \
|
||||
-f hub-documentdb-values.yaml
|
||||
```
|
||||
|
||||
The `hub_values_snippet` output contains credentials, so treat the generated
|
||||
file as a secret and do not commit it.
|
||||
|
||||
### 4. Verify
|
||||
|
||||
```bash
|
||||
kubectl logs -n kerberos-hub deploy/hub-api | head -50
|
||||
kubectl exec -n kerberos-hub deploy/hub-api -- ls -l /certs
|
||||
```
|
||||
|
||||
A one-off connectivity check from inside the cluster:
|
||||
|
||||
```bash
|
||||
kubectl run mongosh --rm -it --restart=Never -n kerberos-hub \
|
||||
--image=mongodb/mongodb-community-server:7.0-ubi8 \
|
||||
--overrides='{"spec":{"volumes":[{"name":"ca","secret":{"secretName":"mongodb-ca"}}],"containers":[{"name":"mongosh","image":"mongodb/mongodb-community-server:7.0-ubi8","stdin":true,"tty":true,"command":["mongosh"],"args":["'"$(terraform output -raw mongodb_uri)"'&tls=true&tlsCAFile=/certs/global-bundle.pem"],"volumeMounts":[{"name":"ca","mountPath":"/certs"}]}]}}'
|
||||
```
|
||||
|
||||
## Persistent volumes
|
||||
|
||||
The EBS CSI driver is installed, but EKS ships `gp2` as the default storage
|
||||
class. To use `gp3` instead:
|
||||
|
||||
```bash
|
||||
kubectl patch storageclass gp2 -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: gp3
|
||||
annotations:
|
||||
storageclass.kubernetes.io/is-default-class: "true"
|
||||
provisioner: ebs.csi.aws.com
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
allowVolumeExpansion: true
|
||||
parameters:
|
||||
type: gp3
|
||||
EOF
|
||||
```
|
||||
|
||||
## Tear down
|
||||
|
||||
```bash
|
||||
# Remove the release first so its load balancers and volumes are cleaned up.
|
||||
helm uninstall hub -n kerberos-hub
|
||||
|
||||
terraform destroy
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
The defaults are tuned for a small test stack. See [variables.tf](variables.tf)
|
||||
for the full list; the ones you are most likely to change:
|
||||
|
||||
| Variable | Default | Description |
|
||||
| -------- | ------- | ----------- |
|
||||
| `name` | `kerberos-hub` | Name prefix for every resource |
|
||||
| `region` | `eu-west-1` | AWS region |
|
||||
| `vpc_cidr` | `10.20.0.0/16` | VPC CIDR block |
|
||||
| `single_nat_gateway` | `true` | One shared NAT gateway (cheaper, not highly available) |
|
||||
| `kubernetes_version` | `1.31` | EKS control plane version |
|
||||
| `cluster_endpoint_public_access_cidrs` | `["0.0.0.0/0"]` | Who may reach the Kubernetes API, **narrow this down** |
|
||||
| `node_instance_types` | `["t3.large"]` | Worker node instance types |
|
||||
| `node_desired_size` | `2` | Number of worker nodes |
|
||||
| `docdb_instance_class` | `db.t3.medium` | DocumentDB instance class |
|
||||
| `docdb_instance_count` | `1` | Number of DocumentDB instances |
|
||||
| `docdb_username` | `kerberos` | Master username |
|
||||
| `docdb_password` | generated | Master password, generated when unset |
|
||||
| `docdb_tls` | `true` | Enforce TLS on the cluster |
|
||||
| `docdb_allowed_cidrs` | `[]` | Extra CIDRs allowed on port 27017 |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Output | Description |
|
||||
| ------ | ----------- |
|
||||
| `cluster_name`, `cluster_endpoint` | EKS cluster identity |
|
||||
| `update_kubeconfig_command` | Ready to run `aws eks update-kubeconfig ...` |
|
||||
| `vpc_id`, `private_subnet_ids` | Networking identifiers |
|
||||
| `docdb_endpoint`, `docdb_reader_endpoint`, `docdb_port` | DocumentDB connection details |
|
||||
| `docdb_username`, `docdb_password` | Master credentials (password is sensitive) |
|
||||
| `mongodb_uri` | Connection string for `mongodb.uri` (sensitive) |
|
||||
| `hub_values_snippet` | Ready to paste helm values including the TLS block (sensitive) |
|
||||
|
||||
## Related
|
||||
|
||||
- [`../amazon-documentdb`](../amazon-documentdb/README.md) — using DocumentDB as the Kerberos Hub metadata store
|
||||
- [`../../overlays/documentdb`](../../overlays/documentdb) — Kustomize overlay that deploys Kerberos Hub against DocumentDB
|
||||
- [`../../README.k8s-managed.md`](../../README.k8s-managed.md) — installing on managed Kubernetes
|
||||
122
modules/amazon-eks-documentdb/documentdb.tf
Normal file
122
modules/amazon-eks-documentdb/documentdb.tf
Normal file
@@ -0,0 +1,122 @@
|
||||
###############################################################################
|
||||
# DocumentDB
|
||||
#
|
||||
# The cluster is created with TLS (encryption in transit) and encryption at
|
||||
# rest enabled. Clients must trust the Amazon RDS certificate authority bundle:
|
||||
#
|
||||
# curl -O https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
|
||||
#
|
||||
# For Kerberos Hub that bundle is mounted through the helm chart's
|
||||
# `mongodb.tls` values, see the README next to this file.
|
||||
###############################################################################
|
||||
|
||||
resource "random_password" "docdb" {
|
||||
count = var.docdb_password == null ? 1 : 0
|
||||
|
||||
length = 32
|
||||
special = true
|
||||
|
||||
# DocumentDB rejects '/', '"' and '@' in the master password. '@' and '/'
|
||||
# would also break the MongoDB connection string.
|
||||
override_special = "!#$%&*()-_=+[]{}<>:?"
|
||||
}
|
||||
|
||||
locals {
|
||||
docdb_password = var.docdb_password != null ? var.docdb_password : random_password.docdb[0].result
|
||||
}
|
||||
|
||||
resource "aws_security_group" "docdb" {
|
||||
name = "${local.name}-docdb"
|
||||
description = "MongoDB wire protocol access to the Kerberos Hub DocumentDB cluster"
|
||||
vpc_id = module.vpc.vpc_id
|
||||
|
||||
tags = merge(local.tags, { Name = "${local.name}-docdb" })
|
||||
}
|
||||
|
||||
resource "aws_vpc_security_group_ingress_rule" "docdb_from_eks_nodes" {
|
||||
security_group_id = aws_security_group.docdb.id
|
||||
description = "DocumentDB from the EKS worker nodes"
|
||||
|
||||
referenced_security_group_id = module.eks.node_security_group_id
|
||||
ip_protocol = "tcp"
|
||||
from_port = 27017
|
||||
to_port = 27017
|
||||
}
|
||||
|
||||
resource "aws_vpc_security_group_ingress_rule" "docdb_from_cidrs" {
|
||||
for_each = toset(var.docdb_allowed_cidrs)
|
||||
|
||||
security_group_id = aws_security_group.docdb.id
|
||||
description = "DocumentDB from ${each.value}"
|
||||
|
||||
cidr_ipv4 = each.value
|
||||
ip_protocol = "tcp"
|
||||
from_port = 27017
|
||||
to_port = 27017
|
||||
}
|
||||
|
||||
resource "aws_docdb_subnet_group" "this" {
|
||||
name = "${local.name}-docdb"
|
||||
description = "Private subnets of the Kerberos Hub VPC"
|
||||
subnet_ids = module.vpc.private_subnets
|
||||
|
||||
tags = local.tags
|
||||
}
|
||||
|
||||
resource "aws_docdb_cluster_parameter_group" "this" {
|
||||
name = "${local.name}-docdb"
|
||||
family = var.docdb_parameter_group_family
|
||||
description = "Kerberos Hub DocumentDB parameters"
|
||||
|
||||
parameter {
|
||||
name = "tls"
|
||||
value = var.docdb_tls ? "enabled" : "disabled"
|
||||
}
|
||||
|
||||
tags = local.tags
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_docdb_cluster" "this" {
|
||||
cluster_identifier = "${local.name}-docdb"
|
||||
engine = "docdb"
|
||||
engine_version = var.docdb_engine_version
|
||||
port = 27017
|
||||
|
||||
master_username = var.docdb_username
|
||||
master_password = local.docdb_password
|
||||
|
||||
db_subnet_group_name = aws_docdb_subnet_group.this.name
|
||||
db_cluster_parameter_group_name = aws_docdb_cluster_parameter_group.this.name
|
||||
vpc_security_group_ids = [aws_security_group.docdb.id]
|
||||
|
||||
storage_encrypted = true
|
||||
kms_key_id = var.docdb_kms_key_id
|
||||
|
||||
backup_retention_period = var.docdb_backup_retention_period
|
||||
preferred_backup_window = "02:00-04:00"
|
||||
preferred_maintenance_window = "sun:04:30-sun:05:30"
|
||||
|
||||
enabled_cloudwatch_logs_exports = var.docdb_enabled_cloudwatch_logs_exports
|
||||
|
||||
deletion_protection = var.docdb_deletion_protection
|
||||
skip_final_snapshot = var.docdb_skip_final_snapshot
|
||||
final_snapshot_identifier = var.docdb_skip_final_snapshot ? null : "${local.name}-docdb-final"
|
||||
|
||||
tags = local.tags
|
||||
}
|
||||
|
||||
resource "aws_docdb_cluster_instance" "this" {
|
||||
count = var.docdb_instance_count
|
||||
|
||||
identifier = "${local.name}-docdb-${count.index}"
|
||||
cluster_identifier = aws_docdb_cluster.this.id
|
||||
instance_class = var.docdb_instance_class
|
||||
|
||||
auto_minor_version_upgrade = true
|
||||
|
||||
tags = local.tags
|
||||
}
|
||||
70
modules/amazon-eks-documentdb/eks.tf
Normal file
70
modules/amazon-eks-documentdb/eks.tf
Normal file
@@ -0,0 +1,70 @@
|
||||
###############################################################################
|
||||
# EKS
|
||||
###############################################################################
|
||||
|
||||
module "eks" {
|
||||
source = "terraform-aws-modules/eks/aws"
|
||||
version = "~> 20.31"
|
||||
|
||||
cluster_name = local.name
|
||||
cluster_version = var.kubernetes_version
|
||||
|
||||
cluster_endpoint_public_access = var.cluster_endpoint_public_access
|
||||
cluster_endpoint_public_access_cidrs = var.cluster_endpoint_public_access_cidrs
|
||||
|
||||
# Give the identity running `terraform apply` cluster-admin, so that
|
||||
# `aws eks update-kubeconfig` immediately works.
|
||||
enable_cluster_creator_admin_permissions = true
|
||||
|
||||
vpc_id = module.vpc.vpc_id
|
||||
subnet_ids = module.vpc.private_subnets
|
||||
|
||||
cluster_addons = {
|
||||
coredns = {}
|
||||
kube-proxy = {}
|
||||
vpc-cni = {}
|
||||
eks-pod-identity-agent = {}
|
||||
aws-ebs-csi-driver = {
|
||||
service_account_role_arn = module.ebs_csi_irsa.iam_role_arn
|
||||
}
|
||||
}
|
||||
|
||||
eks_managed_node_groups = {
|
||||
default = {
|
||||
instance_types = var.node_instance_types
|
||||
capacity_type = "ON_DEMAND"
|
||||
|
||||
min_size = var.node_min_size
|
||||
max_size = var.node_max_size
|
||||
desired_size = var.node_desired_size
|
||||
|
||||
disk_size = var.node_disk_size
|
||||
}
|
||||
}
|
||||
|
||||
tags = local.tags
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# EBS CSI driver
|
||||
#
|
||||
# Kerberos Hub's supporting components (RabbitMQ, VerneMQ, MinIO, ...) claim
|
||||
# persistent volumes, so the cluster needs a working CSI driver.
|
||||
###############################################################################
|
||||
|
||||
module "ebs_csi_irsa" {
|
||||
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
|
||||
version = "~> 5.44"
|
||||
|
||||
role_name = "${local.name}-ebs-csi"
|
||||
attach_ebs_csi_policy = true
|
||||
|
||||
oidc_providers = {
|
||||
main = {
|
||||
provider_arn = module.eks.oidc_provider_arn
|
||||
namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
|
||||
}
|
||||
}
|
||||
|
||||
tags = local.tags
|
||||
}
|
||||
124
modules/amazon-eks-documentdb/outputs.tf
Normal file
124
modules/amazon-eks-documentdb/outputs.tf
Normal file
@@ -0,0 +1,124 @@
|
||||
###############################################################################
|
||||
# Cluster
|
||||
###############################################################################
|
||||
|
||||
output "region" {
|
||||
description = "AWS region the stack is deployed in."
|
||||
value = var.region
|
||||
}
|
||||
|
||||
output "cluster_name" {
|
||||
description = "Name of the EKS cluster."
|
||||
value = module.eks.cluster_name
|
||||
}
|
||||
|
||||
output "cluster_endpoint" {
|
||||
description = "Endpoint of the Kubernetes API server."
|
||||
value = module.eks.cluster_endpoint
|
||||
}
|
||||
|
||||
output "update_kubeconfig_command" {
|
||||
description = "Command to point kubectl at the new cluster."
|
||||
value = "aws eks update-kubeconfig --region ${var.region} --name ${module.eks.cluster_name}"
|
||||
}
|
||||
|
||||
output "vpc_id" {
|
||||
description = "ID of the VPC. DocumentDB is only reachable from inside this VPC."
|
||||
value = module.vpc.vpc_id
|
||||
}
|
||||
|
||||
output "private_subnet_ids" {
|
||||
description = "IDs of the private subnets hosting the worker nodes and DocumentDB."
|
||||
value = module.vpc.private_subnets
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# DocumentDB
|
||||
###############################################################################
|
||||
|
||||
output "docdb_endpoint" {
|
||||
description = "Cluster (writer) endpoint of the DocumentDB cluster."
|
||||
value = aws_docdb_cluster.this.endpoint
|
||||
}
|
||||
|
||||
output "docdb_reader_endpoint" {
|
||||
description = "Reader endpoint of the DocumentDB cluster."
|
||||
value = aws_docdb_cluster.this.reader_endpoint
|
||||
}
|
||||
|
||||
output "docdb_port" {
|
||||
description = "Port the DocumentDB cluster listens on."
|
||||
value = aws_docdb_cluster.this.port
|
||||
}
|
||||
|
||||
output "docdb_username" {
|
||||
description = "DocumentDB master username."
|
||||
value = aws_docdb_cluster.this.master_username
|
||||
}
|
||||
|
||||
output "docdb_password" {
|
||||
description = "DocumentDB master password. Read it with: terraform output -raw docdb_password"
|
||||
value = local.docdb_password
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "docdb_security_group_id" {
|
||||
description = "Security group guarding the DocumentDB cluster."
|
||||
value = aws_security_group.docdb.id
|
||||
}
|
||||
|
||||
output "docdb_tls_enabled" {
|
||||
description = "Whether TLS is enforced on the DocumentDB cluster."
|
||||
value = var.docdb_tls
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Kerberos Hub wiring
|
||||
###############################################################################
|
||||
|
||||
output "mongodb_uri" {
|
||||
description = <<-EOT
|
||||
Connection string for the Kerberos Hub helm chart (`mongodb.uri`).
|
||||
The chart appends `tls=true` and `tlsCAFile=...` itself when
|
||||
`mongodb.tls.enabled=true`, so no TLS parameters are included here.
|
||||
Read it with: terraform output -raw mongodb_uri
|
||||
EOT
|
||||
|
||||
value = format(
|
||||
"mongodb://%s:%s@%s:%d/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false",
|
||||
var.docdb_username,
|
||||
urlencode(local.docdb_password),
|
||||
aws_docdb_cluster.this.endpoint,
|
||||
aws_docdb_cluster.this.port,
|
||||
)
|
||||
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "hub_values_snippet" {
|
||||
description = <<-EOT
|
||||
Ready to paste values for the Kerberos Hub helm chart. Write it to a file with:
|
||||
terraform output -raw hub_values_snippet > hub-documentdb-values.yaml
|
||||
It expects the Amazon RDS CA bundle to be available as the `mongodb-ca` secret:
|
||||
curl -O https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
|
||||
kubectl create secret generic mongodb-ca --from-file=global-bundle.pem -n kerberos-hub
|
||||
EOT
|
||||
|
||||
value = <<-EOT
|
||||
mongodb:
|
||||
# DocumentDB does not support geospatial queries, complex $lookup
|
||||
# pipelines or retryable writes, hence the flavor and retryWrites below.
|
||||
flavor: "documentdb"
|
||||
retryWrites: "false"
|
||||
uri: "mongodb://${var.docdb_username}:${urlencode(local.docdb_password)}@${aws_docdb_cluster.this.endpoint}:${aws_docdb_cluster.this.port}/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
|
||||
adminDatabase: "admin"
|
||||
authenticationMechanism: "SCRAM-SHA-1"
|
||||
tls:
|
||||
enabled: ${var.docdb_tls}
|
||||
existingSecret: "mongodb-ca"
|
||||
caFileName: "global-bundle.pem"
|
||||
mountPath: "/certs"
|
||||
EOT
|
||||
|
||||
sensitive = true
|
||||
}
|
||||
33
modules/amazon-eks-documentdb/terraform.tfvars.example
Normal file
33
modules/amazon-eks-documentdb/terraform.tfvars.example
Normal file
@@ -0,0 +1,33 @@
|
||||
# Copy to terraform.tfvars and adjust.
|
||||
|
||||
name = "kerberos-hub"
|
||||
region = "eu-west-1"
|
||||
environment = "test"
|
||||
|
||||
# Networking
|
||||
vpc_cidr = "10.20.0.0/16"
|
||||
availability_zone_count = 3
|
||||
single_nat_gateway = true
|
||||
|
||||
# EKS
|
||||
kubernetes_version = "1.31"
|
||||
# Restrict this to your office or VPN range.
|
||||
cluster_endpoint_public_access_cidrs = ["0.0.0.0/0"]
|
||||
node_instance_types = ["t3.large"]
|
||||
node_desired_size = 2
|
||||
node_min_size = 2
|
||||
node_max_size = 4
|
||||
|
||||
# DocumentDB
|
||||
docdb_engine_version = "5.0.0"
|
||||
docdb_parameter_group_family = "docdb5.0"
|
||||
docdb_instance_class = "db.t3.medium"
|
||||
docdb_instance_count = 1
|
||||
docdb_username = "kerberos"
|
||||
# Leave docdb_password unset to have one generated:
|
||||
# terraform output -raw docdb_password
|
||||
docdb_tls = true
|
||||
|
||||
# Throwaway test stack settings, flip these for anything long lived.
|
||||
docdb_deletion_protection = false
|
||||
docdb_skip_final_snapshot = true
|
||||
194
modules/amazon-eks-documentdb/variables.tf
Normal file
194
modules/amazon-eks-documentdb/variables.tf
Normal file
@@ -0,0 +1,194 @@
|
||||
###############################################################################
|
||||
# General
|
||||
###############################################################################
|
||||
|
||||
variable "name" {
|
||||
description = "Name prefix used for every resource created by this stack."
|
||||
type = string
|
||||
default = "kerberos-hub"
|
||||
|
||||
validation {
|
||||
condition = can(regex("^[a-z][a-z0-9-]{2,30}$", var.name))
|
||||
error_message = "The name must be lowercase, start with a letter and contain only letters, digits and dashes (3-31 characters)."
|
||||
}
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "AWS region to deploy into."
|
||||
type = string
|
||||
default = "eu-west-1"
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
description = "Environment label applied as a tag (for example test, staging, production)."
|
||||
type = string
|
||||
default = "test"
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Extra tags merged into every resource."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Networking
|
||||
###############################################################################
|
||||
|
||||
variable "vpc_cidr" {
|
||||
description = "CIDR block of the VPC. DocumentDB is only reachable from within this VPC."
|
||||
type = string
|
||||
default = "10.20.0.0/16"
|
||||
}
|
||||
|
||||
variable "availability_zone_count" {
|
||||
description = "Number of availability zones to spread the subnets over. DocumentDB requires at least two."
|
||||
type = number
|
||||
default = 3
|
||||
|
||||
validation {
|
||||
condition = var.availability_zone_count >= 2 && var.availability_zone_count <= 4
|
||||
error_message = "availability_zone_count must be between 2 and 4."
|
||||
}
|
||||
}
|
||||
|
||||
variable "single_nat_gateway" {
|
||||
description = "Use one shared NAT gateway instead of one per availability zone. Cheaper, but not highly available."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# EKS
|
||||
###############################################################################
|
||||
|
||||
variable "kubernetes_version" {
|
||||
description = "Kubernetes version of the EKS control plane."
|
||||
type = string
|
||||
default = "1.31"
|
||||
}
|
||||
|
||||
variable "cluster_endpoint_public_access" {
|
||||
description = "Expose the Kubernetes API server publicly. Keep it on for a test cluster, restrict it with cluster_endpoint_public_access_cidrs."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "cluster_endpoint_public_access_cidrs" {
|
||||
description = "CIDR blocks allowed to reach the public Kubernetes API endpoint. Narrow this to your office/VPN range."
|
||||
type = list(string)
|
||||
default = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
variable "node_instance_types" {
|
||||
description = "Instance types of the managed node group."
|
||||
type = list(string)
|
||||
default = ["t3.large"]
|
||||
}
|
||||
|
||||
variable "node_desired_size" {
|
||||
description = "Desired number of worker nodes."
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "node_min_size" {
|
||||
description = "Minimum number of worker nodes."
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "node_max_size" {
|
||||
description = "Maximum number of worker nodes."
|
||||
type = number
|
||||
default = 4
|
||||
}
|
||||
|
||||
variable "node_disk_size" {
|
||||
description = "EBS volume size (GiB) of each worker node."
|
||||
type = number
|
||||
default = 50
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# DocumentDB
|
||||
###############################################################################
|
||||
|
||||
variable "docdb_engine_version" {
|
||||
description = "DocumentDB engine version."
|
||||
type = string
|
||||
default = "5.0.0"
|
||||
}
|
||||
|
||||
variable "docdb_parameter_group_family" {
|
||||
description = "Parameter group family matching the engine version (docdb5.0, docdb4.0, ...)."
|
||||
type = string
|
||||
default = "docdb5.0"
|
||||
}
|
||||
|
||||
variable "docdb_instance_class" {
|
||||
description = "Instance class of the DocumentDB instances."
|
||||
type = string
|
||||
default = "db.t3.medium"
|
||||
}
|
||||
|
||||
variable "docdb_instance_count" {
|
||||
description = "Number of DocumentDB instances. One is enough for a test stack, use two or more for failover."
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "docdb_username" {
|
||||
description = "DocumentDB master username. 'admin' and other reserved words are rejected by AWS."
|
||||
type = string
|
||||
default = "kerberos"
|
||||
}
|
||||
|
||||
variable "docdb_password" {
|
||||
description = "DocumentDB master password. Leave null to generate one; read it afterwards with 'terraform output -raw docdb_password'."
|
||||
type = string
|
||||
default = null
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "docdb_tls" {
|
||||
description = "Enforce TLS (encryption in transit) on the cluster. Keep this enabled; it is the configuration the hub chart's mongodb.tls values are meant for."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "docdb_kms_key_id" {
|
||||
description = "KMS key ARN for encryption at rest. Leave null to use the AWS managed key."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "docdb_backup_retention_period" {
|
||||
description = "Number of days automated backups are retained."
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "docdb_deletion_protection" {
|
||||
description = "Prevent the cluster from being deleted. Keep false for a throwaway test stack."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "docdb_skip_final_snapshot" {
|
||||
description = "Skip the final snapshot on destroy. Keep true for a throwaway test stack."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "docdb_enabled_cloudwatch_logs_exports" {
|
||||
description = "Log types exported to CloudWatch (audit, profiler)."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "docdb_allowed_cidrs" {
|
||||
description = "Extra CIDR blocks allowed to reach DocumentDB on port 27017, on top of the EKS worker nodes (for example a bastion subnet)."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
18
modules/amazon-eks-documentdb/versions.tf
Normal file
18
modules/amazon-eks-documentdb/versions.tf
Normal file
@@ -0,0 +1,18 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.60"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = ">= 3.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = var.region
|
||||
}
|
||||
59
modules/amazon-eks-documentdb/vpc.tf
Normal file
59
modules/amazon-eks-documentdb/vpc.tf
Normal file
@@ -0,0 +1,59 @@
|
||||
locals {
|
||||
name = var.name
|
||||
|
||||
tags = merge(
|
||||
{
|
||||
Project = "kerberos-hub"
|
||||
Environment = var.environment
|
||||
ManagedBy = "terraform"
|
||||
Module = "deployment/modules/amazon-eks-documentdb"
|
||||
},
|
||||
var.tags,
|
||||
)
|
||||
|
||||
azs = slice(data.aws_availability_zones.available.names, 0, var.availability_zone_count)
|
||||
}
|
||||
|
||||
data "aws_availability_zones" "available" {
|
||||
state = "available"
|
||||
|
||||
filter {
|
||||
name = "opt-in-status"
|
||||
values = ["opt-in-not-required"]
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# VPC
|
||||
#
|
||||
# DocumentDB has no public endpoint: it only listens inside the VPC. Both the
|
||||
# EKS worker nodes and the DocumentDB instances therefore live in the private
|
||||
# subnets, and the workers reach the internet (image pulls) through NAT.
|
||||
###############################################################################
|
||||
|
||||
module "vpc" {
|
||||
source = "terraform-aws-modules/vpc/aws"
|
||||
version = "~> 5.13"
|
||||
|
||||
name = "${local.name}-vpc"
|
||||
cidr = var.vpc_cidr
|
||||
|
||||
azs = local.azs
|
||||
private_subnets = [for index in range(var.availability_zone_count) : cidrsubnet(var.vpc_cidr, 4, index)]
|
||||
public_subnets = [for index in range(var.availability_zone_count) : cidrsubnet(var.vpc_cidr, 4, index + 8)]
|
||||
|
||||
enable_nat_gateway = true
|
||||
single_nat_gateway = var.single_nat_gateway
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
|
||||
public_subnet_tags = {
|
||||
"kubernetes.io/role/elb" = "1"
|
||||
}
|
||||
|
||||
private_subnet_tags = {
|
||||
"kubernetes.io/role/internal-elb" = "1"
|
||||
}
|
||||
|
||||
tags = local.tags
|
||||
}
|
||||
Reference in New Issue
Block a user