diff --git a/aws/platform/main.tf b/aws/platform/main.tf
index 254d96b9..70669747 100644
--- a/aws/platform/main.tf
+++ b/aws/platform/main.tf
@@ -24,6 +24,11 @@ module "common_platform" {
var.cert_manager_values
)
+ cloudwatch_adapter_values = concat(
+ local.cloudwatch_adapter_values,
+ var.cloudwatch_adapter_values
+ )
+
cluster_autoscaler_values = concat(
local.cluster_autoscaler_values,
var.cluster_autoscaler_values
@@ -128,6 +133,15 @@ module "cloudwatch_logs" {
skip_destroy = var.logs_skip_destroy
}
+module "cloudwatch_adapter_service_account_role" {
+ source = "./modules/cloudwatch-adapter-service-account-role"
+
+ aws_namespace = [module.cluster_name.full]
+ aws_tags = var.aws_tags
+ k8s_namespace = var.k8s_namespace
+ oidc_issuer = data.aws_ssm_parameter.oidc_issuer.value
+}
+
module "cluster_autoscaler_service_account_role" {
source = "./modules/cluster-autoscaler-service-account-role"
@@ -251,6 +265,16 @@ locals {
})
]
+ cloudwatch_adapter_values = [
+ yamlencode({
+ serviceAccount = {
+ annotations = {
+ "eks.amazonaws.com/role-arn" = module.cloudwatch_adapter_service_account_role.arn
+ }
+ }
+ })
+ ]
+
cluster_autoscaler_values = [
yamlencode({
autoDiscovery = {
diff --git a/aws/platform/modules/cloudwatch-adapter-service-account-role/README.md b/aws/platform/modules/cloudwatch-adapter-service-account-role/README.md
new file mode 100644
index 00000000..ab2ac79f
--- /dev/null
+++ b/aws/platform/modules/cloudwatch-adapter-service-account-role/README.md
@@ -0,0 +1,44 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.14.8 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 4.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [cluster\_autoscaler\_service\_account\_role](#module\_cluster\_autoscaler\_service\_account\_role) | ../../../service-account-role | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
+| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [aws\_namespace](#input\_aws\_namespace) | Prefix to be applied to created AWS resources | `list(string)` | `[]` | no |
+| [aws\_tags](#input\_aws\_tags) | Tags to be applied to created AWS resources | `map(string)` | `{}` | no |
+| [k8s\_namespace](#input\_k8s\_namespace) | Kubernetes namespace in which resources should be created | `string` | n/a | yes |
+| [oidc\_issuer](#input\_oidc\_issuer) | OIDC issuer of the Kubernetes cluster | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [arn](#output\_arn) | The ARN of the created role |
+| [service\_account\_role\_arn](#output\_service\_account\_role\_arn) | ARN of the AWS IAM role created for service accounts |
+
\ No newline at end of file
diff --git a/aws/platform/modules/cloudwatch-adapter-service-account-role/main.tf b/aws/platform/modules/cloudwatch-adapter-service-account-role/main.tf
new file mode 100644
index 00000000..c05c594d
--- /dev/null
+++ b/aws/platform/modules/cloudwatch-adapter-service-account-role/main.tf
@@ -0,0 +1,28 @@
+module "cloudwatch_adapter_service_account_role" {
+ source = "../../../service-account-role"
+
+ name = "cloudwatch-adapter"
+ namespace = var.aws_namespace
+ oidc_issuers = [var.oidc_issuer]
+ service_accounts = ["${var.k8s_namespace}:cloudwatch-adapter"]
+ tags = var.aws_tags
+}
+
+resource "aws_iam_policy" "this" {
+ name = module.cloudwatch_adapter_service_account_role.name
+ policy = data.aws_iam_policy_document.this.json
+}
+
+resource "aws_iam_role_policy_attachment" "this" {
+ role = module.cloudwatch_adapter_service_account_role.name
+ policy_arn = aws_iam_policy.this.arn
+}
+
+data "aws_iam_policy_document" "this" {
+ statement {
+ actions = [
+ "cloudwatch:GetMetricData"
+ ]
+ resources = ["*"]
+ }
+}
diff --git a/aws/platform/modules/cloudwatch-adapter-service-account-role/makefile b/aws/platform/modules/cloudwatch-adapter-service-account-role/makefile
new file mode 100644
index 00000000..364a9e25
--- /dev/null
+++ b/aws/platform/modules/cloudwatch-adapter-service-account-role/makefile
@@ -0,0 +1,67 @@
+MODULEFILES := $(wildcard *.tf)
+TFLINTRC ?= ../../.tflint.hcl
+TFDOCSRC ?= ../../.terraform-docs.yml
+
+.PHONY: default
+default: checkfmt validate docs lint
+
+.PHONY: checkfmt
+checkfmt: .fmt
+
+.PHONY: fmt
+fmt: $(MODULEFILES)
+ terraform fmt
+ @touch .fmt
+
+.PHONY: validate
+validate: .validate
+
+.PHONY: docs
+docs: README.md
+
+.PHONY: lint
+lint: .lint
+
+.lint: $(MODULEFILES) .lintinit
+ tflint --config=$(TFLINTRC)
+ @touch .lint
+
+.lintinit: $(TFLINTRC)
+ tflint --init --config=$(TFLINTRC) --module
+ @touch .lintinit
+
+README.md: $(MODULEFILES)
+ terraform-docs --config "$(TFDOCSRC)" markdown table . --output-file README.md
+
+.fmt: $(MODULEFILES)
+ terraform fmt -check
+ @touch .fmt
+
+.PHONY: init
+init: .init
+
+.init: versions.tf .dependencies
+ terraform init -backend=false
+ @touch .init
+
+.validate: .init $(MODULEFILES) $(wildcard *.tf.example)
+ echo | cat - $(wildcard *.tf.example) > test.tf
+ if AWS_DEFAULT_REGION=us-east-1 terraform validate; then \
+ rm test.tf; \
+ touch .validate; \
+ else \
+ rm test.tf; \
+ false; \
+ fi
+
+.dependencies: *.tf
+ @grep -ohE \
+ "\b(backend|provider|resource|module) ['\"][[:alpha:]][[:alnum:]]*|\bsource *=.*" *.tf | \
+ sed "s/['\"]//" | sort | uniq | \
+ tee /tmp/initdeps | \
+ diff -q .dependencies - >/dev/null 2>&1 || \
+ mv /tmp/initdeps .dependencies
+
+.PHONY: clean
+clean:
+ rm -rf .dependencies .fmt .init .lint .lintinit .terraform* .validate
diff --git a/aws/platform/modules/cloudwatch-adapter-service-account-role/outputs.tf b/aws/platform/modules/cloudwatch-adapter-service-account-role/outputs.tf
new file mode 100644
index 00000000..d778c65f
--- /dev/null
+++ b/aws/platform/modules/cloudwatch-adapter-service-account-role/outputs.tf
@@ -0,0 +1,9 @@
+output "arn" {
+ description = "The ARN of the created role"
+ value = module.cloudwatch_adapter_service_account_role.instance.arn
+}
+
+output "service_account_role_arn" {
+ description = "ARN of the AWS IAM role created for service accounts"
+ value = module.cloudwatch_adapter_service_account_role.instance.arn
+}
diff --git a/aws/platform/modules/cloudwatch-adapter-service-account-role/variables.tf b/aws/platform/modules/cloudwatch-adapter-service-account-role/variables.tf
new file mode 100644
index 00000000..e0b085c9
--- /dev/null
+++ b/aws/platform/modules/cloudwatch-adapter-service-account-role/variables.tf
@@ -0,0 +1,21 @@
+variable "aws_namespace" {
+ type = list(string)
+ default = []
+ description = "Prefix to be applied to created AWS resources"
+}
+
+variable "aws_tags" {
+ type = map(string)
+ description = "Tags to be applied to created AWS resources"
+ default = {}
+}
+
+variable "k8s_namespace" {
+ type = string
+ description = "Kubernetes namespace in which resources should be created"
+}
+
+variable "oidc_issuer" {
+ type = string
+ description = "OIDC issuer of the Kubernetes cluster"
+}
diff --git a/aws/platform/modules/cloudwatch-adapter-service-account-role/versions.tf b/aws/platform/modules/cloudwatch-adapter-service-account-role/versions.tf
new file mode 100644
index 00000000..020f4777
--- /dev/null
+++ b/aws/platform/modules/cloudwatch-adapter-service-account-role/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+ required_version = ">= 0.14.8"
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}
diff --git a/aws/platform/variables.tf b/aws/platform/variables.tf
index 0c7ae6eb..5e6c4279 100644
--- a/aws/platform/variables.tf
+++ b/aws/platform/variables.tf
@@ -51,6 +51,12 @@ variable "certificate_issuer" {
default = null
}
+variable "cloudwatch_adapter_values" {
+ description = "Overrides to pass to the Helm chart"
+ type = list(string)
+ default = []
+}
+
variable "cluster_autoscaler_values" {
description = "Overrides to pass to the Helm chart"
type = list(string)
diff --git a/platform/main.tf b/platform/main.tf
index 5f17b1ae..794bf878 100644
--- a/platform/main.tf
+++ b/platform/main.tf
@@ -60,6 +60,13 @@ module "cert_manager" {
k8s_namespace = local.flightdeck_namespace
}
+module "cloudwatch_adapter" {
+ source = "./modules/cloudwatch-adapter"
+
+ chart_values = var.cloudwatch_adapter_values
+ k8s_namespace = local.flightdeck_namespace
+}
+
module "cluster_autoscaler" {
source = "./modules/cluster-autoscaler"
diff --git a/platform/modules/cloudwatch-adapter/README.md b/platform/modules/cloudwatch-adapter/README.md
new file mode 100644
index 00000000..5b1b30e7
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/README.md
@@ -0,0 +1,29 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 0.14.8 |
+| [helm](#requirement\_helm) | ~> 2.4 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [helm](#provider\_helm) | ~> 2.4 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [helm_release.ingress_config](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [domain\_names](#input\_domain\_names) | Domains which are allowed in this cluster | `list(string)` | `[]` | no |
+| [issuer](#input\_issuer) | YAML spec for the cert-manager issuer | `string` | `null` | no |
+| [k8s\_namespace](#input\_k8s\_namespace) | Kubernetes namespace in which secrets should be created | `string` | n/a | yes |
+| [name](#input\_name) | Name for the Helm release | `string` | `"ingress-config"` | no |
+
\ No newline at end of file
diff --git a/platform/modules/cloudwatch-adapter/chart/Chart.yaml b/platform/modules/cloudwatch-adapter/chart/Chart.yaml
new file mode 100644
index 00000000..37282ea6
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/chart/Chart.yaml
@@ -0,0 +1,9 @@
+apiVersion: v2
+name: cloudwatch-adapter
+description: Configuration for cloudwatch adapter to fetch AWS Cloudwatch metrics in kubernetes
+
+type: application
+
+version: 0.1.0
+
+appVersion: 1.0.0
diff --git a/platform/modules/cloudwatch-adapter/chart/templates/manifest.yaml b/platform/modules/cloudwatch-adapter/chart/templates/manifest.yaml
new file mode 100644
index 00000000..6c37f99e
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/chart/templates/manifest.yaml
@@ -0,0 +1,204 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: cloudwatch-adapter:system:auth-delegator
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: system:auth-delegator
+subjects:
+- kind: ServiceAccount
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: cloudwatch-adapter-auth-reader
+ namespace: kube-system
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: extension-apiserver-authentication-reader
+subjects:
+- kind: ServiceAccount
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: cloudwatch-adapter
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: cloudwatch-adapter
+ template:
+ metadata:
+ labels:
+ app: cloudwatch-adapter
+ name: cloudwatch-adapter
+ spec:
+ serviceAccountName: cloudwatch-adapter
+ securityContext:
+ fsGroup: 65534
+ containers:
+ - name: cloudwatch-adapter
+ image: chankh/k8s-cloudwatch-adapter:v0.10.0
+ args:
+ - /adapter
+ - --cert-dir=/tmp
+ - --secure-port=6443
+ - --logtostderr=true
+ - --v=2
+ ports:
+ - containerPort: 6443
+ name: https
+ - containerPort: 8080
+ name: http
+ volumeMounts:
+ - mountPath: /tmp
+ name: temp-vol
+ volumes:
+ - name: temp-vol
+ emptyDir: {}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: cloudwatch-adapter-resource-reader
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cloudwatch-adapter-resource-reader
+subjects:
+- kind: ServiceAccount
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{ toYaml . | nindent 4 | trim }}
+ {{- end }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+spec:
+ ports:
+ - name: https
+ port: 443
+ targetPort: 6443
+ - name: http
+ port: 80
+ targetPort: 8080
+ selector:
+ app: cloudwatch-adapter
+---
+apiVersion: apiregistration.k8s.io/v1
+kind: APIService
+metadata:
+ name: v1beta1.external.metrics.k8s.io
+spec:
+ service:
+ name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+ group: external.metrics.k8s.io
+ version: v1beta1
+ insecureSkipTLSVerify: true
+ groupPriorityMinimum: 100
+ versionPriority: 100
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: cloudwatch-adapter:external-metrics-reader
+rules:
+- apiGroups:
+ - external.metrics.k8s.io
+ resources: ["*"]
+ verbs: ["*"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: cloudwatch-adapter-resource-reader
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - namespaces
+ - pods
+ - services
+ - configmaps
+ verbs:
+ - get
+ - list
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: cloudwatch-adapter:external-metrics-reader
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cloudwatch-adapter:external-metrics-reader
+subjects:
+- kind: ServiceAccount
+ name: horizontal-pod-autoscaler
+ namespace: kube-system
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: externalmetrics.metrics.aws
+spec:
+ group: metrics.aws
+ version: v1alpha1
+ names:
+ kind: ExternalMetric
+ plural: externalmetrics
+ singular: externalmetric
+ scope: Namespaced
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: cloudwatch-adapter:crd-metrics-reader
+ labels:
+ app: cloudwatch-adapter
+rules:
+- apiGroups:
+ - metrics.aws
+ resources:
+ - "externalmetrics"
+ verbs:
+ - list
+ - get
+ - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: cloudwatch-adapter:crd-metrics-reader
+ labels:
+ app: cloudwatch-adapter
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cloudwatch-adapter:crd-metrics-reader
+subjects:
+ - name: cloudwatch-adapter
+ namespace: {{ .Release.Namespace }}
+ kind: ServiceAccount
diff --git a/platform/modules/cloudwatch-adapter/chart/values.yaml b/platform/modules/cloudwatch-adapter/chart/values.yaml
new file mode 100644
index 00000000..cfb24e53
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/chart/values.yaml
@@ -0,0 +1,5 @@
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+ annotations: {}
\ No newline at end of file
diff --git a/platform/modules/cloudwatch-adapter/main.tf b/platform/modules/cloudwatch-adapter/main.tf
new file mode 100644
index 00000000..aebe3268
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/main.tf
@@ -0,0 +1,7 @@
+resource "helm_release" "cloudwatch_adapter" {
+ chart = "${path.module}/chart"
+ name = var.name
+ namespace = var.k8s_namespace
+ values = var.chart_values
+}
+
diff --git a/platform/modules/cloudwatch-adapter/makefile b/platform/modules/cloudwatch-adapter/makefile
new file mode 100644
index 00000000..364a9e25
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/makefile
@@ -0,0 +1,67 @@
+MODULEFILES := $(wildcard *.tf)
+TFLINTRC ?= ../../.tflint.hcl
+TFDOCSRC ?= ../../.terraform-docs.yml
+
+.PHONY: default
+default: checkfmt validate docs lint
+
+.PHONY: checkfmt
+checkfmt: .fmt
+
+.PHONY: fmt
+fmt: $(MODULEFILES)
+ terraform fmt
+ @touch .fmt
+
+.PHONY: validate
+validate: .validate
+
+.PHONY: docs
+docs: README.md
+
+.PHONY: lint
+lint: .lint
+
+.lint: $(MODULEFILES) .lintinit
+ tflint --config=$(TFLINTRC)
+ @touch .lint
+
+.lintinit: $(TFLINTRC)
+ tflint --init --config=$(TFLINTRC) --module
+ @touch .lintinit
+
+README.md: $(MODULEFILES)
+ terraform-docs --config "$(TFDOCSRC)" markdown table . --output-file README.md
+
+.fmt: $(MODULEFILES)
+ terraform fmt -check
+ @touch .fmt
+
+.PHONY: init
+init: .init
+
+.init: versions.tf .dependencies
+ terraform init -backend=false
+ @touch .init
+
+.validate: .init $(MODULEFILES) $(wildcard *.tf.example)
+ echo | cat - $(wildcard *.tf.example) > test.tf
+ if AWS_DEFAULT_REGION=us-east-1 terraform validate; then \
+ rm test.tf; \
+ touch .validate; \
+ else \
+ rm test.tf; \
+ false; \
+ fi
+
+.dependencies: *.tf
+ @grep -ohE \
+ "\b(backend|provider|resource|module) ['\"][[:alpha:]][[:alnum:]]*|\bsource *=.*" *.tf | \
+ sed "s/['\"]//" | sort | uniq | \
+ tee /tmp/initdeps | \
+ diff -q .dependencies - >/dev/null 2>&1 || \
+ mv /tmp/initdeps .dependencies
+
+.PHONY: clean
+clean:
+ rm -rf .dependencies .fmt .init .lint .lintinit .terraform* .validate
diff --git a/platform/modules/cloudwatch-adapter/outputs.tf b/platform/modules/cloudwatch-adapter/outputs.tf
new file mode 100644
index 00000000..e69de29b
diff --git a/platform/modules/cloudwatch-adapter/variables.tf b/platform/modules/cloudwatch-adapter/variables.tf
new file mode 100644
index 00000000..8995a498
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/variables.tf
@@ -0,0 +1,16 @@
+variable "chart_values" {
+ description = "Overrides to pass to the Helm chart"
+ type = list(string)
+ default = []
+}
+
+variable "k8s_namespace" {
+ type = string
+ description = "Kubernetes namespace in which secrets should be created"
+}
+
+variable "name" {
+ description = "Name for the Helm release"
+ type = string
+ default = "cloudwatch-adapter"
+}
diff --git a/platform/modules/cloudwatch-adapter/versions.tf b/platform/modules/cloudwatch-adapter/versions.tf
new file mode 100644
index 00000000..0ed6889f
--- /dev/null
+++ b/platform/modules/cloudwatch-adapter/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+ required_version = ">= 0.14.8"
+ required_providers {
+ helm = {
+ source = "hashicorp/helm"
+ version = "~> 2.4"
+ }
+ }
+}
diff --git a/platform/variables.tf b/platform/variables.tf
index 3243ce56..e8dc621e 100644
--- a/platform/variables.tf
+++ b/platform/variables.tf
@@ -16,6 +16,12 @@ variable "certificate_issuer" {
default = null
}
+variable "cloudwatch_adapter_values" {
+ description = "Overrides to pass to the Helm chart"
+ type = list(string)
+ default = []
+}
+
variable "cluster_autoscaler_values" {
description = "Overrides to pass to the Helm chart"
type = list(string)