Skip to content

Commit 5b52c7b

Browse files
authored
GitOps support with Grafana Operator, External Secrets and FluxCD (#151)
* Adding FluxCD and Grafana Operator Addons * Adding Helm release for Grafana Operator * Adding External Secrets * removing spot options * Fixing Documentation ---------
1 parent b513fe4 commit 5b52c7b

File tree

14 files changed

+391
-2
lines changed

14 files changed

+391
-2
lines changed

docs/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ traces collection, dashboards and alerts for monitoring:
2525
- NGINX workloads (running on Amazon EKS)
2626
- Java/JMX workloads (running on Amazon EKS)
2727
- Amazon Managed Service for Prometheus workspaces with Amazon CloudWatch
28+
- Installs Grafana Operator to add AWS data sources and create Grafana Dashboards to Amazon Managed Grafana.
29+
- Installs FluxCD to perform GitOps sync of a Git Repo to EKS Cluster. We will use this later for creating Grafana Dashboards and AWS datasources to Amazon Managed Grafana.
30+
- Installs External Secrets Operator to retrieve and Sync the Grafana API keys.
2831

2932
These modules can be directly configured in your existing Terraform
3033
configurations or ready to be deployed in our packaged

examples/existing-cluster-java/main.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ module "eks_monitoring" {
6969
# enable java metrics collection, dashboards and alerts rules creation
7070
enable_java = true
7171

72+
# deploys external-secrets in to the cluster
73+
enable_external_secrets = true
74+
grafana_api_key = var.grafana_api_key
75+
target_secret_name = "grafana-admin-credentials"
76+
target_secret_namespace = "grafana-operator"
77+
7278
eks_cluster_id = var.eks_cluster_id
7379

7480
# control the publishing of dashboards by specifying the boolean value for the variable 'enable_dashboards', default is 'true'

examples/existing-cluster-nginx/main.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ module "eks_monitoring" {
6767

6868
eks_cluster_id = var.eks_cluster_id
6969

70+
# deploys external-secrets in to the cluster
71+
enable_external_secrets = true
72+
grafana_api_key = var.grafana_api_key
73+
target_secret_name = "grafana-admin-credentials"
74+
target_secret_namespace = "grafana-operator"
75+
7076
# control the publishing of dashboards by specifying the boolean value for the variable 'enable_dashboards', default is 'true'
7177
# the intention to publish is overruled depending upon whether grafana dashboard folder is created by the observability accelerator
7278
enable_dashboards = module.aws_observability_accelerator.grafana_dashboard_folder_created ? var.enable_dashboards : false

examples/existing-cluster-with-base-and-infra/main.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ module "eks_monitoring" {
7777
# reusing existing certificate manager? defaults to true
7878
enable_cert_manager = true
7979

80+
# deploys external-secrets in to the cluster
81+
enable_external_secrets = true
82+
grafana_api_key = var.grafana_api_key
83+
target_secret_name = "grafana-admin-credentials"
84+
target_secret_namespace = "grafana-operator"
85+
8086
# control the publishing of dashboards by specifying the boolean value for the variable 'enable_dashboards', default is 'true'
8187
# the intention to publish is overruled depending upon whether grafana dashboard folder is created by the observability accelerator
8288
enable_dashboards = module.aws_observability_accelerator.grafana_dashboard_folder_created ? var.enable_dashboards : false

modules/eks-monitoring/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ This module provides EKS cluster monitoring with the following resources:
44

55
- AWS Distro For OpenTelemetry Operator and Collector for Metrics and Traces
66
- Logs with [AWS for FluentBit](https://github.com/aws/aws-for-fluent-bit)
7-
- AWS Managed Grafana Dashboard and data source
7+
- Installs Grafana Operator to add AWS data sources and create Grafana Dashboards to Amazon Managed Grafana.
8+
- Installs FluxCD to perform GitOps sync of a Git Repo to EKS Cluster. We will use this later for creating Grafana Dashboards and AWS datasources to Amazon Managed Grafana.
9+
- Installs External Secrets Operator to retrieve and Sync the Grafana API keys.
10+
- Amazon Managed Grafana Dashboard and data source
811
- Alerts and recording rules with AWS Managed Service for Prometheus
912

1013
This module makes use of the open source [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)
@@ -33,6 +36,7 @@ This module makes use of the open source [kube-prometheus-stack](https://github.
3336

3437
| Name | Source | Version |
3538
|------|--------|---------|
39+
| <a name="module_external_secrets"></a> [external\_secrets](#module\_external\_secrets) | ./add-ons/external-secrets | n/a |
3640
| <a name="module_fluentbit_logs"></a> [fluentbit\_logs](#module\_fluentbit\_logs) | ./add-ons/aws-for-fluentbit | n/a |
3741
| <a name="module_helm_addon"></a> [helm\_addon](#module\_helm\_addon) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons/helm-addon | v4.26.0 |
3842
| <a name="module_java_monitoring"></a> [java\_monitoring](#module\_java\_monitoring) | ./patterns/java | n/a |
@@ -51,6 +55,8 @@ This module makes use of the open source [kube-prometheus-stack](https://github.
5155
| [grafana_dashboard.nodes](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/dashboard) | resource |
5256
| [grafana_dashboard.nsworkload](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/dashboard) | resource |
5357
| [grafana_dashboard.workloads](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/dashboard) | resource |
58+
| [helm_release.fluxcd](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
59+
| [helm_release.grafana_operator](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
5460
| [helm_release.kube_state_metrics](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
5561
| [helm_release.prometheus_node_exporter](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
5662
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
@@ -70,13 +76,19 @@ This module makes use of the open source [kube-prometheus-stack](https://github.
7076
| <a name="input_enable_cert_manager"></a> [enable\_cert\_manager](#input\_enable\_cert\_manager) | Allow reusing an existing installation of cert-manager | `bool` | `true` | no |
7177
| <a name="input_enable_custom_metrics"></a> [enable\_custom\_metrics](#input\_enable\_custom\_metrics) | Allows additional metrics collection for config elements in the `custom_metrics_config` config object. Automatic dashboards are not included | `bool` | `false` | no |
7278
| <a name="input_enable_dashboards"></a> [enable\_dashboards](#input\_enable\_dashboards) | Enables or disables curated dashboards | `bool` | `true` | no |
79+
| <a name="input_enable_external_secrets"></a> [enable\_external\_secrets](#input\_enable\_external\_secrets) | Installs External Secrets to EKS Cluster | `bool` | `true` | no |
80+
| <a name="input_enable_fluxcd"></a> [enable\_fluxcd](#input\_enable\_fluxcd) | Enables or disables FluxCD. Disabling this might affect some data in the dashboards | `bool` | `true` | no |
81+
| <a name="input_enable_grafana_operator"></a> [enable\_grafana\_operator](#input\_enable\_grafana\_operator) | Deploys Grafana Operator to EKS Cluster | `bool` | `true` | no |
7382
| <a name="input_enable_java"></a> [enable\_java](#input\_enable\_java) | Enable Java workloads monitoring, alerting and default dashboards | `bool` | `false` | no |
7483
| <a name="input_enable_kube_state_metrics"></a> [enable\_kube\_state\_metrics](#input\_enable\_kube\_state\_metrics) | Enables or disables Kube State metrics exporter. Disabling this might affect some data in the dashboards | `bool` | `true` | no |
7584
| <a name="input_enable_logs"></a> [enable\_logs](#input\_enable\_logs) | Using AWS For FluentBit to collect cluster and application logs to Amazon CloudWatch | `bool` | `true` | no |
7685
| <a name="input_enable_nginx"></a> [enable\_nginx](#input\_enable\_nginx) | Enable NGINX workloads monitoring, alerting and default dashboards | `bool` | `false` | no |
7786
| <a name="input_enable_node_exporter"></a> [enable\_node\_exporter](#input\_enable\_node\_exporter) | Enables or disables Node exporter. Disabling this might affect some data in the dashboards | `bool` | `true` | no |
7887
| <a name="input_enable_recording_rules"></a> [enable\_recording\_rules](#input\_enable\_recording\_rules) | Enables or disables Managed Prometheus recording rules | `bool` | `true` | no |
7988
| <a name="input_enable_tracing"></a> [enable\_tracing](#input\_enable\_tracing) | (Experimental) Enables tracing with AWS X-Ray. This changes the deploy mode of the collector to daemon set. Requirement: adot add-on <= 0.58-build.0 | `bool` | `false` | no |
89+
| <a name="input_flux_config"></a> [flux\_config](#input\_flux\_config) | FluxCD configuration | <pre>object({<br> create_namespace = bool<br> k8s_namespace = string<br> helm_chart_name = string<br> helm_chart_version = string<br> helm_release_name = string<br> helm_repo_url = string<br> helm_settings = map(string)<br> helm_values = map(any)<br> })</pre> | <pre>{<br> "create_namespace": true,<br> "helm_chart_name": "flux2",<br> "helm_chart_version": "2.7.0",<br> "helm_release_name": "observability-fluxcd-addon",<br> "helm_repo_url": "https://fluxcd-community.github.io/helm-charts",<br> "helm_settings": {},<br> "helm_values": {},<br> "k8s_namespace": "flux-system"<br>}</pre> | no |
90+
| <a name="input_go_config"></a> [go\_config](#input\_go\_config) | Grafana Operator configuration | <pre>object({<br> create_namespace = bool<br> helm_chart = string<br> helm_name = string<br> k8s_namespace = string<br> helm_release_name = string<br> helm_chart_version = string<br> })</pre> | <pre>{<br> "create_namespace": true,<br> "helm_chart": "oci://ghcr.io/grafana-operator/helm-charts/grafana-operator",<br> "helm_chart_version": "v5.0.0-rc1",<br> "helm_name": "grafana-operator",<br> "helm_release_name": "grafana-operator",<br> "k8s_namespace": "grafana-operator"<br>}</pre> | no |
91+
| <a name="input_grafana_api_key"></a> [grafana\_api\_key](#input\_grafana\_api\_key) | Grafana API key for the Amazon Managed Grafana workspace | `string` | n/a | yes |
8092
| <a name="input_helm_config"></a> [helm\_config](#input\_helm\_config) | Helm Config for Prometheus | `any` | `{}` | no |
8193
| <a name="input_irsa_iam_permissions_boundary"></a> [irsa\_iam\_permissions\_boundary](#input\_irsa\_iam\_permissions\_boundary) | IAM permissions boundary for IRSA roles | `string` | `null` | no |
8294
| <a name="input_irsa_iam_role_path"></a> [irsa\_iam\_role\_path](#input\_irsa\_iam\_role\_path) | IAM role path for IRSA roles | `string` | `"/"` | no |
@@ -90,6 +102,8 @@ This module makes use of the open source [kube-prometheus-stack](https://github.
90102
| <a name="input_nginx_config"></a> [nginx\_config](#input\_nginx\_config) | Configuration object for NGINX monitoring | <pre>object({<br> enable_alerting_rules = bool<br> scrape_sample_limit = number<br> prometheus_metrics_endpoint = string<br> })</pre> | <pre>{<br> "enable_alerting_rules": true,<br> "prometheus_metrics_endpoint": "metrics",<br> "scrape_sample_limit": 1000<br>}</pre> | no |
91103
| <a name="input_prometheus_config"></a> [prometheus\_config](#input\_prometheus\_config) | Controls default values such as scrape interval, timeouts and ports globally | <pre>object({<br> global_scrape_interval = string<br> global_scrape_timeout = string<br> })</pre> | <pre>{<br> "global_scrape_interval": "60s",<br> "global_scrape_timeout": "15s"<br>}</pre> | no |
92104
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `map('BusinessUnit`,`XYZ`) | `map(string)` | `{}` | no |
105+
| <a name="input_target_secret_name"></a> [target\_secret\_name](#input\_target\_secret\_name) | Target secret in Kubernetes to store the Grafana API Key Secret | `string` | `"grafana-admin-credentials"` | no |
106+
| <a name="input_target_secret_namespace"></a> [target\_secret\_namespace](#input\_target\_secret\_namespace) | Target namespace of secret in Kubernetes to store the Grafana API Key Secret | `string` | `"grafana-operator"` | no |
93107
| <a name="input_tracing_config"></a> [tracing\_config](#input\_tracing\_config) | Configuration object for traces collection to AWS X-Ray | <pre>object({<br> otlp_grpc_endpoint = string<br> otlp_http_endpoint = string<br> send_batch_size = number<br> timeout = string<br> })</pre> | <pre>{<br> "otlp_grpc_endpoint": "0.0.0.0:4317",<br> "otlp_http_endpoint": "0.0.0.0:4318",<br> "send_batch_size": 50,<br> "timeout": "30s"<br>}</pre> | no |
94108

95109
## Outputs
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# External Secrets Operator Kubernetes addon
2+
3+
This deploys an EKS Cluster with the External Secrets Operator. The cluster is populated with a ClusterSecretStore and ExternalSecret using Grafana API Key secret from AWS Secret Manager. A secret store for each AWS Secret Manager is created. Store use IRSA (IAM Roles For Service Account) to retrieve the secret values from AWS.
4+
5+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
6+
## Requirements
7+
8+
| Name | Version |
9+
|------|---------|
10+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
11+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.72 |
12+
| <a name="requirement_kubectl"></a> [kubectl](#requirement\_kubectl) | >= 1.14 |
13+
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | >= 2.10 |
14+
15+
## Providers
16+
17+
| Name | Version |
18+
|------|---------|
19+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 3.72 |
20+
| <a name="provider_kubectl"></a> [kubectl](#provider\_kubectl) | >= 1.14 |
21+
22+
## Modules
23+
24+
| Name | Source | Version |
25+
|------|--------|---------|
26+
| <a name="module_cluster_secretstore_role"></a> [cluster\_secretstore\_role](#module\_cluster\_secretstore\_role) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/irsa | v4.28.0 |
27+
| <a name="module_external_secrets"></a> [external\_secrets](#module\_external\_secrets) | github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons/external-secrets | v4.28.0 |
28+
29+
## Resources
30+
31+
| Name | Type |
32+
|------|------|
33+
| [aws_iam_policy.cluster_secretstore](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
34+
| [aws_kms_key.secrets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
35+
| [aws_secretsmanager_secret.secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
36+
| [aws_secretsmanager_secret_version.secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
37+
| [kubectl_manifest.cluster_secretstore](https://registry.terraform.io/providers/gavinbunney/kubectl/latest/docs/resources/manifest) | resource |
38+
| [kubectl_manifest.secret](https://registry.terraform.io/providers/gavinbunney/kubectl/latest/docs/resources/manifest) | resource |
39+
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
40+
41+
## Inputs
42+
43+
| Name | Description | Type | Default | Required |
44+
|------|-------------|------|---------|:--------:|
45+
| <a name="input_addon_context"></a> [addon\_context](#input\_addon\_context) | Input configuration for the addon | <pre>object({<br> aws_caller_identity_account_id = string<br> aws_caller_identity_arn = string<br> aws_eks_cluster_endpoint = string<br> aws_partition_id = string<br> aws_region_name = string<br> eks_cluster_id = string<br> eks_oidc_issuer_url = string<br> eks_oidc_provider_arn = string<br> irsa_iam_role_path = string<br> irsa_iam_permissions_boundary = string<br> tags = map(string)<br> })</pre> | n/a | yes |
46+
| <a name="input_enable_external_secrets"></a> [enable\_external\_secrets](#input\_enable\_external\_secrets) | Enable external-secrets | `bool` | `true` | no |
47+
| <a name="input_grafana_api_key"></a> [grafana\_api\_key](#input\_grafana\_api\_key) | Grafana API key for the Amazon Managed Grafana workspace | `string` | n/a | yes |
48+
| <a name="input_helm_config"></a> [helm\_config](#input\_helm\_config) | Helm provider config for external secrets | `any` | `{}` | no |
49+
| <a name="input_target_secret_name"></a> [target\_secret\_name](#input\_target\_secret\_name) | Name to store the secret for Grafana API Key | `string` | n/a | yes |
50+
| <a name="input_target_secret_namespace"></a> [target\_secret\_namespace](#input\_target\_secret\_namespace) | Namespace to store the secret for Grafana API Key | `string` | n/a | yes |
51+
52+
## Outputs
53+
54+
No outputs.
55+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
locals {
2+
name = "external-secrets"
3+
namespace = "external-secrets"
4+
cluster_secretstore_name = "cluster-secretstore-sm"
5+
cluster_secretstore_sa = "cluster-secretstore-sa"
6+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
module "external_secrets" {
2+
source = "github.com/aws-ia/terraform-aws-eks-blueprints//modules/kubernetes-addons/external-secrets?ref=v4.28.0"
3+
count = var.enable_external_secrets ? 1 : 0
4+
5+
helm_config = var.helm_config
6+
addon_context = var.addon_context
7+
}
8+
9+
data "aws_region" "current" {}
10+
11+
#---------------------------------------------------------------
12+
# External Secrets Operator - Secret
13+
#---------------------------------------------------------------
14+
15+
resource "aws_kms_key" "secrets" {
16+
enable_key_rotation = true
17+
}
18+
19+
module "cluster_secretstore_role" {
20+
source = "github.com/aws-ia/terraform-aws-eks-blueprints//modules/irsa?ref=v4.28.0"
21+
kubernetes_namespace = local.namespace
22+
create_kubernetes_namespace = false
23+
kubernetes_service_account = local.cluster_secretstore_sa
24+
irsa_iam_policies = [aws_iam_policy.cluster_secretstore.arn]
25+
eks_cluster_id = var.addon_context.eks_cluster_id
26+
eks_oidc_provider_arn = var.addon_context.eks_oidc_provider_arn
27+
depends_on = [module.external_secrets]
28+
}
29+
30+
resource "aws_iam_policy" "cluster_secretstore" {
31+
name_prefix = local.cluster_secretstore_sa
32+
policy = <<POLICY
33+
{
34+
"Version": "2012-10-17",
35+
"Statement": [
36+
{
37+
"Effect": "Allow",
38+
"Action": [
39+
"secretsmanager:GetResourcePolicy",
40+
"secretsmanager:GetSecretValue",
41+
"secretsmanager:DescribeSecret",
42+
"secretsmanager:ListSecretVersionIds"
43+
],
44+
"Resource": "${aws_secretsmanager_secret.secret.arn}"
45+
},
46+
{
47+
"Effect": "Allow",
48+
"Action": [
49+
"kms:Decrypt"
50+
],
51+
"Resource": "${aws_kms_key.secrets.arn}"
52+
}
53+
]
54+
}
55+
POLICY
56+
}
57+
58+
resource "kubectl_manifest" "cluster_secretstore" {
59+
yaml_body = <<YAML
60+
apiVersion: external-secrets.io/v1beta1
61+
kind: ClusterSecretStore
62+
metadata:
63+
name: ${local.cluster_secretstore_name}
64+
spec:
65+
provider:
66+
aws:
67+
service: SecretsManager
68+
region: ${data.aws_region.current.name}
69+
auth:
70+
jwt:
71+
serviceAccountRef:
72+
name: ${local.cluster_secretstore_sa}
73+
namespace: ${local.namespace}
74+
YAML
75+
depends_on = [module.external_secrets]
76+
}
77+
78+
resource "aws_secretsmanager_secret" "secret" {
79+
recovery_window_in_days = 0
80+
kms_key_id = aws_kms_key.secrets.arn
81+
}
82+
83+
resource "aws_secretsmanager_secret_version" "secret" {
84+
secret_id = aws_secretsmanager_secret.secret.id
85+
secret_string = jsonencode({
86+
GF_SECURITY_ADMIN_APIKEY = var.grafana_api_key
87+
})
88+
}
89+
90+
resource "kubectl_manifest" "secret" {
91+
yaml_body = <<YAML
92+
apiVersion: external-secrets.io/v1beta1
93+
kind: ExternalSecret
94+
metadata:
95+
name: ${local.name}-sm
96+
namespace: ${var.target_secret_namespace}
97+
spec:
98+
refreshInterval: 1h
99+
secretStoreRef:
100+
name: ${local.cluster_secretstore_name}
101+
kind: ClusterSecretStore
102+
target:
103+
name: ${var.target_secret_name}
104+
dataFrom:
105+
- extract:
106+
key: ${aws_secretsmanager_secret.secret.name}
107+
YAML
108+
depends_on = [module.external_secrets]
109+
}

modules/eks-monitoring/add-ons/external-secrets/outputs.tf

Whitespace-only changes.

0 commit comments

Comments
 (0)