diff --git a/terraform/provision/2048_fixture.yml b/terraform/provision/2048_fixture.yml index ec9cb84c..dbf513e7 100644 --- a/terraform/provision/2048_fixture.yml +++ b/terraform/provision/2048_fixture.yml @@ -1,4 +1,16 @@ --- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: deployment-2048-cert + namespace: default +spec: + dnsNames: + - "deployment-2048.default.svc.cluster.local" + secretName: deployment-2048-tls + issuerRef: + name: ca-issuer +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -12,13 +24,24 @@ spec: metadata: labels: app.kubernetes.io/name: app-2048 + annotations: + appmesh.k8s.aws/secretMounts: ca-key-pair:/etc/keys/2048/ spec: + serviceAccountName: appmesh-pod containers: - image: alexwhen/docker-2048 imagePullPolicy: Always name: app-2048 ports: - containerPort: 80 + volumeMounts: + - mountPath: "/etc/keys/2048" + name: deployment-2048-tls + readOnly: true + volumes: + - name: deployment-2048-tls + secret: + secretName: deployment-2048-tls --- apiVersion: v1 kind: Service @@ -33,21 +56,155 @@ spec: selector: app.kubernetes.io/name: app-2048 --- -apiVersion: networking.k8s.io/v1 -kind: Ingress +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + namespace: default + name: deployment-2048 +spec: + awsName: deployment-2048-virtual-node + podSelector: + matchLabels: + app.kubernetes.io/name: app-2048 + listeners: + - portMapping: + port: 80 + protocol: http + tls: + certificate: + file: + certificateChain: /etc/keys/2048/tls.crt + privateKey: /etc/keys/2048/tls.key + mode: STRICT + serviceDiscovery: + dns: + hostname: service-2048.default.svc.cluster.local + backendDefaults: + clientPolicy: + tls: + enforce: true + validation: + trust: + file: + certificateChain: /etc/keys/2048/ca.crt +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + namespace: default + name: service-2048 +spec: + awsName: service-2048-virtual-service + provider: + virtualNode: + virtualNodeRef: + name: deployment-2048 + +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: gw-2048-cert + namespace: default +spec: + dnsNames: + - "gw-2048.default.svc.cluster.local" + secretName: gw-2048-tls + issuerRef: + name: ca-issuer +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gw-2048 + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: gw-2048 + template: + metadata: + labels: + app: gw-2048 + annotations: + appmesh.k8s.aws/secretMounts: ca-key-pair:/etc/keys/2048/ + spec: + serviceAccountName: appmesh-pod + containers: + - name: envoy + image: 840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.19.1.0-prod + ports: + - containerPort: 8443 + volumeMounts: + - mountPath: "/etc/keys/2048" + name: gw-2048-tls + readOnly: true + volumes: + - name: gw-2048-tls + secret: + secretName: gw-2048-tls +--- +apiVersion: v1 +kind: Service metadata: - name: ingress-2048 + name: gw-2048 + namespace: default annotations: - kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/rewrite-target: / -spec: - rules: - - http: - paths: - - path: / - pathType: Prefix - backend: - service: + service.beta.kubernetes.io/aws-load-balancer-type: "nlb" + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "ssl" +spec: + ports: + - port: 443 + targetPort: 8443 + name: https + type: LoadBalancer + selector: + app: gw-2048 +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualGateway +metadata: + name: gw-2048 + namespace: default +spec: + backendDefaults: + clientPolicy: + tls: + enforce: true + namespaceSelector: + matchLabels: + mesh: default + podSelector: + matchLabels: + app: gw-2048 + gatewayRouteSelector: + matchLabels: + gateway: gw-2048 + listeners: + - portMapping: + port: 8443 + protocol: http + tls: + certificate: + file: + certificateChain: /etc/keys/2048/tls.crt + privateKey: /etc/keys/2048/tls.key + mode: STRICT +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: GatewayRoute +metadata: + name: gateway-route + namespace: default + labels: + gateway: gw-2048 +spec: + httpRoute: + match: + prefix: "/" + action: + target: + virtualService: + virtualServiceRef: name: service-2048 - port: - number: 80 \ No newline at end of file diff --git a/terraform/provision/appmesh.tf b/terraform/provision/appmesh.tf new file mode 100644 index 00000000..935d821d --- /dev/null +++ b/terraform/provision/appmesh.tf @@ -0,0 +1,389 @@ +# --------------------------------------------------------- +# Provision cert-manager using Helm and a self-signed cert +# --------------------------------------------------------- +resource "kubernetes_namespace" "cert-manager" { + metadata { + name = "cert-manager" + } + + depends_on = [ + aws_eks_fargate_profile.default_namespaces + ] +} + +resource "helm_release" "cert-manager" { + name = "cert-manager" + chart = "cert-manager" + repository = "https://charts.jetstack.io/" + version = "v1.5.3" + namespace = "cert-manager" + cleanup_on_fail = "true" + atomic = "true" + timeout = 600 + + set { + name = "installCRDs" + value = "true" + } + set { + # https://github.com/jetstack/cert-manager/issues/3237 + name = "webhook.securePort" + value = "10260" + } + + depends_on = [ + kubernetes_namespace.cert-manager + ] +} + +# XXX should probably use aws_acmpca_certificate_authority here? +# Sounds like there should be a way to wire ACM in. +# Maybe https://github.com/cert-manager/aws-privateca-issuer ? +resource "tls_private_key" "cert-manager" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "tls_self_signed_cert" "cert-manager" { + key_algorithm = "RSA" + private_key_pem = tls_private_key.cert-manager.private_key_pem + + subject { + common_name = "appmesh" + organization = "GSA" + } + + validity_period_hours = 87600 + is_ca_certificate = true + + allowed_uses = [ + "key_encipherment", + "digital_signature", + "server_auth", + "client_auth", + "cert_signing" + ] +} + +resource "kubernetes_secret" "cert-manager" { + metadata { + name = "ca-key-pair" + namespace = "default" + } + type = "kubernetes.io/tls" + + data = { + "tls.crt" = tls_self_signed_cert.cert-manager.cert_pem + "tls.key" = tls_private_key.cert-manager.private_key_pem + } +} + +# Until we can use terraform 0.14+, and thus be able to use kubernetes_manifest, +# we need to do this with kubectl. :-( +data "template_file" "ca-issuer" { + template = <<-EOF +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: ca-issuer + namespace: default +spec: + ca: + secretName: ca-key-pair +EOF +} + +resource "null_resource" "ca-issuer" { + provisioner "local-exec" { + interpreter = ["/bin/bash", "-c"] + environment = { + KUBECONFIG = base64encode(module.eks.kubeconfig) + } + command = <<-EOF + kubectl --kubeconfig <(echo $KUBECONFIG | base64 -d) apply -f <(echo '${data.template_file.ca-issuer.rendered}') + EOF + } + depends_on = [ + helm_release.cert-manager, + kubernetes_secret.cert-manager + ] +} + + +# --------------------------------------------------------- +# Provision the App Mesh Controller using Helm +# --------------------------------------------------------- +resource "kubernetes_namespace" "appmesh-system" { + metadata { + name = "appmesh-system" + } + + depends_on = [ + null_resource.ca-issuer + ] +} + +# This role is assigned with IRSA to the appmesh controller +resource "aws_iam_role" "appmesh-controller" { + name = "appmesh-controller-${local.cluster_name}" + tags = var.labels + assume_role_policy = <