;
27 |
28 | CREATE SCHEMA IF NOT EXISTS postgres_exporter;
29 | GRANT USAGE ON SCHEMA postgres_exporter TO postgres_exporter;
30 | GRANT CONNECT ON DATABASE postgres TO postgres_exporter;
31 |
32 | CREATE OR REPLACE FUNCTION get_pg_stat_activity() RETURNS SETOF pg_stat_activity AS
33 | $$ SELECT * FROM pg_catalog.pg_stat_activity; $$
34 | LANGUAGE sql
35 | VOLATILE
36 | SECURITY DEFINER;
37 |
38 | CREATE OR REPLACE VIEW postgres_exporter.pg_stat_activity
39 | AS
40 | SELECT * from get_pg_stat_activity();
41 |
42 | GRANT SELECT ON postgres_exporter.pg_stat_activity TO postgres_exporter;
43 |
44 | CREATE OR REPLACE FUNCTION get_pg_stat_replication() RETURNS SETOF pg_stat_replication AS
45 | $$ SELECT * FROM pg_catalog.pg_stat_replication; $$
46 | LANGUAGE sql
47 | VOLATILE
48 | SECURITY DEFINER;
49 |
50 | CREATE OR REPLACE VIEW postgres_exporter.pg_stat_replication
51 | AS
52 | SELECT * FROM get_pg_stat_replication();
53 |
54 | GRANT SELECT ON postgres_exporter.pg_stat_replication TO postgres_exporter;
55 |
56 | CREATE OR REPLACE FUNCTION get_pg_stat_statements() RETURNS SETOF pg_stat_statements AS
57 | $$ SELECT * FROM public.pg_stat_statements; $$
58 | LANGUAGE sql
59 | VOLATILE
60 | SECURITY DEFINER;
61 |
62 | CREATE OR REPLACE VIEW postgres_exporter.pg_stat_statements
63 | AS
64 | SELECT * FROM get_pg_stat_statements();
65 |
66 | GRANT SELECT ON postgres_exporter.pg_stat_statements TO postgres_exporter;
67 |
--------------------------------------------------------------------------------
/terraform/modules/eks-kubernetes-namespace/README.md:
--------------------------------------------------------------------------------
1 | ## Requirements
2 |
3 | No requirements.
4 |
5 | ## Providers
6 |
7 | | Name | Version |
8 | |------|---------|
9 | | [kubernetes](#provider\_kubernetes) | n/a |
10 |
11 | ## Modules
12 |
13 | No modules.
14 |
15 | ## Resources
16 |
17 | | Name | Type |
18 | |------|------|
19 | | [kubernetes_limit_range.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/limit_range) | resource |
20 | | [kubernetes_namespace.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
21 | | [kubernetes_network_policy.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/network_policy) | resource |
22 | | [kubernetes_resource_quota.this](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/resource_quota) | resource |
23 |
24 | ## Inputs
25 |
26 | | Name | Description | Type | Default | Required |
27 | |------|-------------|------|---------|:--------:|
28 | | [annotations](#input\_annotations) | An unstructured key value map stored with the namespace that may be used to store arbitrary metadata | `map(any)` | `{}` | no |
29 | | [depends](#input\_depends) | Indicates the resource this resource depends on. | `any` | `null` | no |
30 | | [enable](#input\_enable) | If set to true, create namespace | `bool` | `true` | no |
31 | | [labels](#input\_labels) | Map of string keys and values that can be used to organize and categorize (scope and select) namespaces. | `map(any)` | `{}` | no |
32 | | [limits](#input\_limits) | n/a | `any` | [
{
"default": {
"memory": "128Mi"
},
"default_request": {
"cpu": "100m",
"memory": "64Mi"
},
"type": "Container"
}
]
| no |
33 | | [name](#input\_name) | Name of the namespace, must be unique. Cannot be updated. | `string` | n/a | yes |
34 | | [network\_policies](#input\_network\_policies) | n/a | `any` | `[]` | no |
35 | | [resource\_quotas](#input\_resource\_quotas) | n/a | `any` | `[]` | no |
36 |
37 | ## Outputs
38 |
39 | | Name | Description |
40 | |------|-------------|
41 | | [labels\_name](#output\_labels\_name) | The value of the name label |
42 | | [name](#output\_name) | The name of the created namespace (from object metadata) |
43 |
--------------------------------------------------------------------------------
/examples/wordpress-deployment-external-secrets.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: wordpress
5 | labels:
6 | app: wordpress
7 | spec:
8 | ports:
9 | - port: 80
10 | selector:
11 | app: wordpress
12 | tier: frontend
13 | ---
14 | apiVersion: v1
15 | kind: PersistentVolumeClaim
16 | metadata:
17 | name: wp-pv-claim
18 | labels:
19 | app: wordpress
20 | spec:
21 | accessModes:
22 | - ReadWriteOnce
23 | resources:
24 | requests:
25 | storage: 20Gi
26 | ---
27 | apiVersion: apps/v1
28 | kind: Deployment
29 | metadata:
30 | annotations:
31 | secret.reloader.stakater.com/reload: "wp"
32 | name: wordpress
33 | labels:
34 | app: wordpress
35 | spec:
36 | selector:
37 | matchLabels:
38 | app: wordpress
39 | tier: frontend
40 | strategy:
41 | type: Recreate
42 | template:
43 | metadata:
44 | annotations:
45 | co.elastic.metrics/module: apache
46 | co.elastic.metrics/hosts: '${data.host}:80'
47 | co.elastic.logs/module: apache
48 | co.elastic.logs/fileset.stdout: access
49 | co.elastic.logs/fileset.stderr: error
50 | labels:
51 | app: wordpress
52 | tier: frontend
53 | spec:
54 | containers:
55 | - image: wordpress:5.4.2-apache
56 | name: wordpress
57 | envFrom:
58 | - secretRef:
59 | name: wp
60 | ports:
61 | - containerPort: 80
62 | name: wordpress
63 | volumeMounts:
64 | - name: wordpress-persistent-storage
65 | mountPath: /var/www/html
66 | volumes:
67 | - name: wordpress-persistent-storage
68 | persistentVolumeClaim:
69 | claimName: wp-pv-claim
70 | ---
71 | apiVersion: extensions/v1beta1
72 | kind: Ingress
73 | metadata:
74 | name: wordpress
75 |
76 | annotations:
77 | kubernetes.io/ingress.class: "nginx"
78 | nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
79 | spec:
80 | rules:
81 | - host: wp.maddevs.org
82 | http:
83 | paths:
84 | - path: /
85 | backend:
86 | serviceName: wordpress
87 | servicePort: 80
88 | ---
89 | apiVersion: 'kubernetes-client.io/v1'
90 | kind: ExternalSecret
91 | metadata:
92 | name: wp
93 | spec:
94 | backendType: systemManager
95 | # roleArn:
96 | data:
97 | - key: /wp/database/username
98 | name: WORDPRESS_DB_USER
99 | - key: /wp/database/password
100 | name: WORDPRESS_DB_PASSWORD
101 | - key: /wp/database/database
102 | name: WORDPRESS_DB_NAME
103 | - key: /wp/database/address
104 | name: WORDPRESS_DB_HOST
--------------------------------------------------------------------------------
/terraform/layer2-k8s/eks-keda.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | keda = {
3 | name = local.helm_releases[index(local.helm_releases.*.id, "keda")].id
4 | enabled = local.helm_releases[index(local.helm_releases.*.id, "keda")].enabled
5 | chart = local.helm_releases[index(local.helm_releases.*.id, "keda")].chart
6 | repository = local.helm_releases[index(local.helm_releases.*.id, "keda")].repository
7 | chart_version = local.helm_releases[index(local.helm_releases.*.id, "keda")].chart_version
8 | namespace = local.helm_releases[index(local.helm_releases.*.id, "keda")].namespace
9 | }
10 | }
11 |
12 | module "keda_namespace" {
13 | count = local.keda.enabled ? 1 : 0
14 |
15 | source = "../modules/eks-kubernetes-namespace"
16 | name = local.keda.namespace
17 | network_policies = [
18 | {
19 | name = "default-deny"
20 | policy_types = ["Ingress", "Egress"]
21 | pod_selector = {}
22 | },
23 | {
24 | name = "allow-this-namespace"
25 | policy_types = ["Ingress"]
26 | pod_selector = {}
27 | ingress = {
28 | from = [
29 | {
30 | namespace_selector = {
31 | match_labels = {
32 | name = local.keda.namespace
33 | }
34 | }
35 | }
36 | ]
37 | }
38 | },
39 | {
40 | name = "allow-egress"
41 | policy_types = ["Egress"]
42 | pod_selector = {}
43 | egress = {
44 | to = [
45 | {
46 | ip_block = {
47 | cidr = "0.0.0.0/0"
48 | except = [
49 | "169.254.169.254/32"
50 | ]
51 | }
52 | }
53 | ]
54 | }
55 | },
56 | {
57 | name = "allow-control-plane"
58 | policy_types = ["Ingress"]
59 | pod_selector = {
60 | match_expressions = {
61 | key = "app"
62 | operator = "In"
63 | values = ["keda-operator-metrics-apiserver"]
64 | }
65 | }
66 | ingress = {
67 | ports = [
68 | {
69 | port = "6443"
70 | protocol = "TCP"
71 | }
72 | ]
73 | from = [
74 | {
75 | ip_block = {
76 | cidr = "0.0.0.0/0"
77 | }
78 | }
79 | ]
80 | }
81 | }
82 | ]
83 | }
84 |
85 | resource "helm_release" "kedacore" {
86 | count = local.keda.enabled ? 1 : 0
87 |
88 | name = local.keda.name
89 | chart = local.keda.chart
90 | repository = local.keda.repository
91 | version = local.keda.chart_version
92 | namespace = module.keda_namespace[count.index].name
93 | max_history = var.helm_release_history_size
94 | }
95 |
--------------------------------------------------------------------------------
/terraform/layer1-aws/aws-cloudtrail.tf:
--------------------------------------------------------------------------------
1 | #tfsec:ignore:aws-cloudtrail-enable-at-rest-encryption tfsec:ignore:aws-cloudtrail-ensure-cloudwatch-integration
2 | resource "aws_cloudtrail" "main" {
3 | name = local.name
4 | s3_bucket_name = aws_s3_bucket.cloudtrail.id
5 | include_global_service_events = true
6 | enable_log_file_validation = true
7 | enable_logging = true
8 | is_multi_region_trail = true
9 |
10 | tags = local.tags
11 |
12 | depends_on = [aws_s3_bucket_policy.cloudtrail]
13 | }
14 |
15 | #tfsec:ignore:aws-s3-enable-bucket-logging tfsec:ignore:aws-s3-enable-versioning tfsec:ignore:aws-cloudtrail-require-bucket-access-logging
16 | resource "aws_s3_bucket" "cloudtrail" {
17 | bucket = "${local.name}-aws-cloudtrail-logs"
18 |
19 | tags = local.tags
20 | }
21 |
22 | resource "aws_s3_bucket_lifecycle_configuration" "cloudtrail" {
23 | bucket = aws_s3_bucket.cloudtrail.id
24 |
25 | rule {
26 | id = "remove_old_files"
27 | status = "Enabled"
28 |
29 | abort_incomplete_multipart_upload {
30 | days_after_initiation = 2
31 | }
32 | expiration {
33 | days = var.cloudtrail_logs_s3_expiration_days
34 | }
35 | }
36 | }
37 |
38 | #tfsec:ignore:aws-s3-encryption-customer-key
39 | resource "aws_s3_bucket_server_side_encryption_configuration" "cloudtrail" {
40 | bucket = aws_s3_bucket.cloudtrail.bucket
41 |
42 | rule {
43 | apply_server_side_encryption_by_default {
44 | sse_algorithm = "AES256"
45 | }
46 | }
47 | }
48 |
49 | resource "aws_s3_bucket_public_access_block" "cloudtrail" {
50 | bucket = aws_s3_bucket.cloudtrail.id
51 | restrict_public_buckets = true
52 | block_public_acls = true
53 | block_public_policy = true
54 | ignore_public_acls = true
55 | }
56 |
57 | resource "aws_s3_bucket_policy" "cloudtrail" {
58 | bucket = aws_s3_bucket.cloudtrail.id
59 |
60 | policy = jsonencode(
61 | {
62 | "Version" : "2012-10-17",
63 | "Statement" : [
64 | {
65 | "Sid" : "AWSCloudTrailAclCheck",
66 | "Effect" : "Allow",
67 | "Principal" : {
68 | "Service" : "cloudtrail.amazonaws.com"
69 | },
70 | "Action" : "s3:GetBucketAcl",
71 | "Resource" : aws_s3_bucket.cloudtrail.arn
72 | },
73 | {
74 | "Sid" : "AWSCloudTrailWrite",
75 | "Effect" : "Allow",
76 | "Principal" : {
77 | "Service" : "cloudtrail.amazonaws.com"
78 | },
79 | "Action" : "s3:PutObject",
80 | "Resource" : "${aws_s3_bucket.cloudtrail.arn}/*",
81 | "Condition" : {
82 | "StringEquals" : {
83 | "s3:x-amz-acl" : "bucket-owner-full-control"
84 | }
85 | }
86 | }
87 | ]
88 | })
89 | }
90 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/visualstudiocode,linux,helm,macos,terraform,windows
2 | # Edit at https://www.gitignore.io/?templates=visualstudiocode,linux,helm,macos,terraform,windows
3 |
4 | .idea/
5 |
6 | ### Linux ###
7 | *~
8 |
9 | # temporary files which can be created if a process still has a handle open of a deleted file
10 | .fuse_hidden*
11 |
12 | # KDE directory preferences
13 | .directory
14 |
15 | # Linux trash folder which might appear on any partition or disk
16 | .Trash-*
17 |
18 | # .nfs files are created when an open file is removed but is still being accessed
19 | .nfs*
20 |
21 | ### macOS ###
22 | # General
23 | .DS_Store
24 | .AppleDouble
25 | .LSOverride
26 |
27 | # Icon must end with two \r
28 | Icon
29 |
30 | # Thumbnails
31 | ._*
32 |
33 | # Files that might appear in the root of a volume
34 | .DocumentRevisions-V100
35 | .fseventsd
36 | .Spotlight-V100
37 | .TemporaryItems
38 | .Trashes
39 | .VolumeIcon.icns
40 | .com.apple.timemachine.donotpresent
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
49 | ### Terraform ###
50 | # Local .terraform directories
51 | **/.terraform/*
52 | **/.terragrunt-cache/*
53 |
54 | # .tfstate files
55 | *.tfstate
56 | *.tfstate.*
57 |
58 | # Crash log files
59 | crash.log
60 |
61 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most
62 | # .tfvars files are managed as part of configuration and so should be included in
63 | # version control.
64 | #
65 | **/*.tfvars
66 | **/backend.tf
67 |
68 | # Ignore override files as they are usually used to override resources locally and so
69 | # are not checked in
70 | override.tf
71 | override.tf.json
72 | *_override.tf
73 | *_override.tf.json
74 |
75 | # Include override files you do wish to add to version control using negated pattern
76 | # !example_override.tf
77 |
78 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
79 | # example: *tfplan*
80 |
81 | ### VisualStudioCode ###
82 | .vscode/*
83 | !.vscode/settings.json
84 | !.vscode/tasks.json
85 | !.vscode/launch.json
86 | !.vscode/extensions.json
87 |
88 | ### VisualStudioCode Patch ###
89 | # Ignore all local history of files
90 | .history
91 |
92 | ### Windows ###
93 | # Windows thumbnail cache files
94 | Thumbs.db
95 | Thumbs.db:encryptable
96 | ehthumbs.db
97 | ehthumbs_vista.db
98 |
99 | # Dump file
100 | *.stackdump
101 |
102 | # Folder config file
103 | [Dd]esktop.ini
104 |
105 | # Recycle Bin used on file shares
106 | $RECYCLE.BIN/
107 |
108 | # Windows Installer files
109 | *.cab
110 | *.msi
111 | *.msix
112 | *.msm
113 | *.msp
114 |
115 | # Windows shortcuts
116 | *.lnk
117 |
118 | **/temp/*
119 |
--------------------------------------------------------------------------------
/examples/wordpress-deployment.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: wordpress
5 | namespace: wp
6 | labels:
7 | app: wordpress
8 | spec:
9 | ports:
10 | - port: 80
11 | selector:
12 | app: wordpress
13 | tier: frontend
14 | ---
15 | apiVersion: v1
16 | kind: PersistentVolumeClaim
17 | metadata:
18 | name: wp-pv-claim
19 | namespace: wp
20 | labels:
21 | app: wordpress
22 | spec:
23 | accessModes:
24 | - ReadWriteOnce
25 | resources:
26 | requests:
27 | storage: 20Gi
28 | ---
29 | apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
30 | kind: Deployment
31 | metadata:
32 | name: wordpress
33 | namespace: wp
34 | labels:
35 | app: wordpress
36 | spec:
37 | selector:
38 | matchLabels:
39 | app: wordpress
40 | tier: frontend
41 | strategy:
42 | type: Recreate
43 | template:
44 | metadata:
45 | annotations:
46 | co.elastic.metrics/module: apache
47 | co.elastic.metrics/hosts: '${data.host}:80'
48 | co.elastic.logs/module: apache
49 | co.elastic.logs/fileset.stdout: access
50 | co.elastic.logs/fileset.stderr: error
51 | labels:
52 | app: wordpress
53 | tier: frontend
54 | spec:
55 | containers:
56 | - image: wordpress:5.4.2-apache
57 | name: wordpress
58 | env:
59 | - name: WORDPRESS_DB_HOST
60 | valueFrom:
61 | secretKeyRef:
62 | name: mysql-connection
63 | key: db-host
64 | - name: WORDPRESS_DB_PASSWORD
65 | valueFrom:
66 | secretKeyRef:
67 | name: mysql-connection
68 | key: db-password
69 | - name: WORDPRESS_DB_NAME
70 | valueFrom:
71 | secretKeyRef:
72 | name: mysql-connection
73 | key: db-name
74 | - name: WORDPRESS_DB_USER
75 | valueFrom:
76 | secretKeyRef:
77 | name: mysql-connection
78 | key: db-user
79 | ports:
80 | - containerPort: 80
81 | name: wordpress
82 | volumeMounts:
83 | - name: wordpress-persistent-storage
84 | mountPath: /var/www/html
85 | volumes:
86 | - name: wordpress-persistent-storage
87 | persistentVolumeClaim:
88 | claimName: wp-pv-claim
89 | ---
90 | apiVersion: extensions/v1beta1
91 | kind: Ingress
92 | metadata:
93 | name: wordpress
94 | namespace: wp
95 | annotations:
96 | kubernetes.io/ingress.class: "nginx"
97 | nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
98 | spec:
99 | rules:
100 | - host: wp.maddevs.org
101 | http:
102 | paths:
103 | - path: /
104 | backend:
105 | serviceName: wordpress
106 | servicePort: 80
107 |
108 |
--------------------------------------------------------------------------------
/terraform/modules/aws-pritunl/iam.tf:
--------------------------------------------------------------------------------
1 | data "aws_iam_policy_document" "this" {
2 | statement {
3 | sid = "AllowMountEFS"
4 | actions = [
5 | "elasticfilesystem:ClientMount",
6 | "elasticfilesystem:ClientWrite"
7 | ]
8 | resources = [
9 | "arn:aws:elasticfilesystem:*:*:file-system/${aws_efs_file_system.this.id}"
10 | ]
11 |
12 | condition {
13 | test = "Bool"
14 | variable = "aws:SecureTransport"
15 |
16 | values = [var.encrypted]
17 | }
18 | }
19 |
20 | statement {
21 | sid = "AllowAssociateEIP"
22 | actions = ["ec2:AssociateAddress"]
23 | resources = ["arn:aws:ec2:*:*:elastic-ip/${aws_eip.this.id}",
24 | "arn:aws:ec2:*:*:instance/*"
25 | ]
26 |
27 | condition {
28 | test = "StringEquals"
29 | variable = "ec2:ResourceTag/Name"
30 |
31 | values = [var.name]
32 | }
33 | }
34 |
35 | statement {
36 | sid = "AllowDisassociateAddressEIP"
37 | actions = ["ec2:DisassociateAddress"]
38 | resources = ["arn:aws:ec2:*:*:elastic-ip/${aws_eip.this.id}",
39 | "arn:aws:ec2:*:*:instance/*"
40 | ]
41 | }
42 |
43 | statement {
44 | sid = "AllowModifyInstanceAttribute"
45 | actions = ["ec2:ModifyInstanceAttribute"]
46 | resources = ["arn:aws:ec2:*:*:instance/*"]
47 |
48 | condition {
49 | test = "StringEquals"
50 | variable = "ec2:ResourceTag/Name"
51 |
52 | values = [var.name]
53 | }
54 | }
55 | }
56 |
57 | module "iam_policy" {
58 | source = "terraform-aws-modules/iam/aws//modules/iam-policy"
59 | version = "4.14.0"
60 |
61 | name = var.name
62 | path = "/"
63 | description = "${var.name} policy"
64 |
65 | policy = data.aws_iam_policy_document.this.json
66 | }
67 |
68 | module "this_role" {
69 | source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
70 | version = "4.14.0"
71 |
72 | trusted_role_services = [
73 | "ec2.amazonaws.com"
74 | ]
75 |
76 | create_role = true
77 |
78 | role_name = var.name
79 | role_requires_mfa = false
80 |
81 | custom_role_policy_arns = [
82 | module.iam_policy.arn,
83 | "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
84 | ]
85 | }
86 |
87 | resource "aws_iam_instance_profile" "this_instance_profile" {
88 | name = var.name
89 | role = module.this_role.iam_role_name
90 | }
91 |
92 | module "backup_role" {
93 | source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
94 | version = "4.14.0"
95 |
96 | trusted_role_services = [
97 | "backup.amazonaws.com"
98 | ]
99 |
100 | create_role = true
101 |
102 | role_name = "${var.name}-backup-role"
103 | role_requires_mfa = false
104 |
105 | custom_role_policy_arns = [
106 | "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
107 | ]
108 | }
109 |
--------------------------------------------------------------------------------
/.github/workflows/terraform-ci.yml:
--------------------------------------------------------------------------------
1 | name: "Terraform-ci"
2 |
3 | on: [push, pull_request]
4 |
5 | defaults:
6 | run:
7 | shell: sh
8 |
9 | jobs:
10 | # Terraform validate configuration
11 | terraform-validate:
12 | name: "Terraform-validate"
13 | runs-on: ubuntu-latest
14 | container:
15 | image: maddevsio/terraform-utils:latest
16 | env:
17 | PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | - name: Terraform Init l1
22 | working-directory: ./terraform/layer1-aws
23 | run: terraform init -backend=false
24 | - name: Terraform Init l2
25 | working-directory: ./terraform/layer2-k8s
26 | run: terraform init -backend=false
27 | - name: Terraform Validate l1
28 | working-directory: ./terraform/layer1-aws
29 | run: terraform validate -no-color .
30 | - name: Terraform Validate l2
31 | working-directory: ./terraform/layer2-k8s
32 | run: terraform validate -no-color .
33 | - name: Upload files for l1
34 | uses: actions/upload-artifact@v2
35 | with:
36 | name: l1
37 | path: ./terraform/layer1-aws/.terraform
38 | retention-days: 1
39 |
40 | # Checks that all Terraform configuration files format
41 | terraform-format:
42 | name: "Terraform-format"
43 | runs-on: ubuntu-latest
44 | container:
45 | image: maddevsio/terraform-utils:latest
46 | env:
47 | PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
48 | steps:
49 | - name: Checkout
50 | uses: actions/checkout@v2
51 | - name: Terraform Format
52 | run: terraform fmt -recursive -write=false -check .
53 | working-directory: ./terraform
54 |
55 | # Checks that all Terraform configuration files tflint
56 | terraform-tflint:
57 | name: "Terraform-tflint"
58 | runs-on: ubuntu-latest
59 | container:
60 | image: maddevsio/terraform-utils:latest
61 | env:
62 | PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
63 | steps:
64 | - name: Checkout
65 | uses: actions/checkout@v2
66 | - name: Terraform tflint l1
67 | working-directory: ./terraform/layer1-aws
68 | run: tflint --no-color
69 | - name: Terraform tflint l2
70 | working-directory: ./terraform/layer2-k8s
71 | run: tflint --no-color
72 |
73 | terraform-tfsec-l1:
74 | name: "Terraform-tfsec-l1"
75 | needs: terraform-validate
76 | runs-on: ubuntu-latest
77 | container:
78 | image: aquasec/tfsec
79 | options: --user root
80 | steps:
81 | - name: Checkout
82 | uses: actions/checkout@v2
83 | - name: Download init for l1
84 | uses: actions/download-artifact@v2
85 | with:
86 | name: l1
87 | path: ./terraform/layer1-aws/.terraform
88 | - name: tfsec l1
89 | working-directory: ./terraform
90 | run: tfsec layer1-aws
91 | - uses: geekyeggo/delete-artifact@v1
92 | with:
93 | name: l1
94 | failOnError: false
95 | if: ${{ always() }}
96 |
--------------------------------------------------------------------------------
/terraform/modules/aws-wafv2-top-10-owasp-rules/variables.tf:
--------------------------------------------------------------------------------
1 | variable "wafv2_rule_action" {
2 | type = string
3 | default = "block"
4 | description = "Default rules action"
5 | }
6 |
7 | variable "waf_scope" {
8 | type = string
9 | default = "CLOUDFRONT"
10 | description = "One API can be used for both global and regional applications. Possible values are CLOUDFRONT and REGIONAL. REGIONAL is used for ALBs, API Gateway"
11 | }
12 |
13 | variable "name" {
14 | type = string
15 | description = "Name used for all resources in this module"
16 | }
17 |
18 | variable "max_expected_uri_size" {
19 | type = string
20 | default = "512"
21 | description = "Maximum number of bytes allowed in the URI component of the HTTP request. Generally the maximum possible value is determined by the server operating system (maps to file system paths), the web server software, or other middleware components. Choose a value that accomodates the largest URI segment you use in practice in your web application."
22 | }
23 |
24 | variable "max_expected_query_string_size" {
25 | type = string
26 | default = "1024"
27 | description = "Maximum number of bytes allowed in the query string component of the HTTP request. Normally the of query string parameters following the ? in a URL is much larger than the URI , but still bounded by the of the parameters your web application uses and their values."
28 | }
29 |
30 | variable "max_expected_body_size" {
31 | type = string
32 | default = "4096"
33 | description = "Maximum number of bytes allowed in the body of the request. If you do not plan to allow large uploads, set it to the largest payload value that makes sense for your web application. Accepting unnecessarily large values can cause performance issues, if large payloads are used as an attack vector against your web application."
34 | }
35 |
36 | variable "max_expected_cookie_size" {
37 | type = string
38 | default = "4093"
39 | description = "Maximum number of bytes allowed in the cookie header. The maximum size should be less than 4096, the size is determined by the amount of information your web application stores in cookies. If you only pass a session token via cookies, set the size to no larger than the serialized size of the session token and cookie metadata."
40 | }
41 |
42 | variable "csrf_expected_header" {
43 | type = string
44 | default = "x-csrf-token"
45 | description = "The custom HTTP request header, where the CSRF token value is expected to be encountered"
46 | }
47 |
48 | variable "csrf_expected_size" {
49 | type = string
50 | default = "36"
51 | description = "The size in bytes of the CSRF token value. For example if it's a canonically formatted UUIDv4 value the expected size would be 36 bytes/ASCII characters."
52 | }
53 |
54 | variable "blacklisted_cidrs" {
55 | type = list(string)
56 | default = ["10.0.0.0/8", "192.168.0.0/16", "169.254.0.0/16", "172.16.0.0/16", "127.0.0.1/32"]
57 | description = "A list of blacklister CIDR blocks"
58 | }
59 |
60 | variable "cloudwatch_metrics_enabled" {
61 | type = bool
62 | default = false
63 | description = "Enable or not using AWS Cloudwatch metrics"
64 | }
65 |
--------------------------------------------------------------------------------
/terraform/layer2-k8s/helm-releases.yaml:
--------------------------------------------------------------------------------
1 | releases:
2 | - id: aws-load-balancer-controller
3 | enabled: true
4 | chart: aws-load-balancer-controller
5 | repository: https://aws.github.io/eks-charts
6 | chart_version: 1.5.1
7 | namespace: aws-load-balancer-controller
8 | - id: cert-manager
9 | enabled: false
10 | chart: cert-manager
11 | repository: https://charts.jetstack.io
12 | chart_version: 1.11.0
13 | namespace: certmanager
14 | - id: cert-mananger-certificate
15 | enabled: false
16 | chart: certificate
17 | repository:
18 | chart_version:
19 | namespace: ingress-nginx
20 | - id: cert-manager-cluster-issuer
21 | enabled: false
22 | chart: cluster-issuer
23 | repository:
24 | chart_version:
25 | namespace: certmanager
26 | - id: elk
27 | enabled: false
28 | chart: elk
29 | repository:
30 | chart_version:
31 | namespace: elk
32 | - id: external-dns
33 | enabled: false
34 | chart: external-dns
35 | repository: https://kubernetes-sigs.github.io/external-dns
36 | chart_version: 1.9.0
37 | namespace: external-dns
38 | - id: external-secrets
39 | enabled: true
40 | chart: external-secrets
41 | repository: https://charts.external-secrets.io
42 | chart_version: 0.8.1
43 | namespace: external-secrets
44 | - id: gitlab-runner
45 | enabled: false
46 | chart: gitlab-runner
47 | repository: https://charts.gitlab.io
48 | chart_version: 0.51.1
49 | namespace: gitlab-runner
50 | - id: ingress-nginx
51 | enabled: true
52 | chart: ingress-nginx
53 | repository: https://kubernetes.github.io/ingress-nginx
54 | chart_version: 4.6.0
55 | namespace: ingress-nginx
56 | - id: istio
57 | enabled: false
58 | chart:
59 | repository: https://istio-release.storage.googleapis.com/charts
60 | chart_version: 1.17.2
61 | namespace: istio-system
62 | - id: karpenter
63 | enabled: true
64 | chart: karpenter
65 | repository: oci://public.ecr.aws/karpenter
66 | chart_version: v0.33.0
67 | namespace: karpenter
68 | - id: keda
69 | enabled: false
70 | chart: keda
71 | repository: https://kedacore.github.io/charts
72 | chart_version: 2.10.2
73 | namespace: keda
74 | - id: kiali
75 | enabled: false
76 | chart: kiali-server
77 | repository: https://kiali.org/helm-charts
78 | chart_version: 1.66.0
79 | namespace: kiali
80 | - id: kube-prometheus-stack
81 | enabled: true
82 | chart: kube-prometheus-stack
83 | repository: https://prometheus-community.github.io/helm-charts
84 | chart_version: 45.11.0
85 | namespace: monitoring
86 | - id: loki-stack
87 | enabled: true
88 | chart: loki-stack
89 | repository: https://grafana.github.io/helm-charts
90 | chart_version: 2.9.10
91 | namespace: loki
92 | - id: reloader
93 | enabled: true
94 | chart: reloader
95 | repository: https://stakater.github.io/stakater-charts
96 | chart_version: 1.0.22
97 | namespace: reloader
98 | - id: victoria-metrics-k8s-stack
99 | enabled: false
100 | chart: victoria-metrics-k8s-stack
101 | repository: https://victoriametrics.github.io/helm-charts
102 | chart_version: 0.14.17
103 | namespace: monitoring
104 |
--------------------------------------------------------------------------------
/docker/postgresql-backups/backup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | import os
3 | import sys
4 | import requests
5 | import boto3
6 | import subprocess
7 | import json
8 | from datetime import datetime
9 |
10 |
11 | def send_slack_notification(slack_url, message, color):
12 | if slack_url is None:
13 | print("Slack web hook not defined")
14 | else:
15 | title = "New Incoming Message :zap:"
16 | slack_data = {
17 | "username": "Backup Notification bot",
18 | "icon_emoji": ":satellite:",
19 | "attachments": [
20 | {
21 | "title": title,
22 | "color": color,
23 | "text": message,
24 | }
25 | ]
26 | }
27 | byte_length = str(sys.getsizeof(slack_data))
28 | headers = {'Content-Type': "application/json", 'Content-Length': byte_length}
29 | response = requests.post(slack_url, data=json.dumps(slack_data), headers=headers)
30 | if response.status_code != 200:
31 | raise Exception(response.status_code, response.text)
32 |
33 |
34 | def backup_postgres_db(host, database_name, port, user, password, dest_file):
35 | try:
36 | process = subprocess.Popen(
37 | ['pg_dump',
38 | '--dbname=postgresql://{}:{}@{}:{}/{}'.format(user, password, host, port, database_name),
39 | '-f', dest_file,
40 | '-v'],
41 | stdout=subprocess.PIPE
42 | )
43 | output = process.communicate()[0]
44 | if int(process.returncode) != 0:
45 | print('Command failed. Return code : {}'.format(process.returncode))
46 | return 1
47 | return output
48 | except Exception as e:
49 | print(e)
50 | return 1
51 |
52 |
53 | def upload_to_s3(file_full_path, aws_bucket_name, dest_obj_path, aws_bucket_region):
54 | s3_client = boto3.client('s3', region_name=aws_bucket_region)
55 |
56 | try:
57 | print(f"Upload file {file_full_path} to S3 bucket {aws_bucket_name}/{dest_obj_path}")
58 | s3_client.upload_file(file_full_path, aws_bucket_name, dest_obj_path)
59 | os.remove(file_full_path)
60 | return 0
61 | except boto3.exceptions.S3UploadFailedError as exc:
62 | print(exc)
63 | return 1
64 |
65 |
66 | if __name__ == '__main__':
67 | # This variable is optional.
68 | SLACK_URL = os.getenv('SLACK_URL')
69 |
70 | AWS_BUCKET_REGION = os.environ['AWS_BUCKET_REGION']
71 | AWS_BUCKET_NAME = os.environ['AWS_BUCKET_NAME']
72 | PG_HOST = os.environ['PG_HOST']
73 | PG_USER = os.environ['PG_USER']
74 | PG_DATABASE = os.environ['PG_DATABASE']
75 | PG_PORT = os.environ['PG_PORT']
76 | PG_PASS = os.environ['PG_PASS']
77 |
78 | dest_path = datetime.strftime(datetime.now(), "%Y/%B/")
79 | source_path = "/tmp/"
80 | dumpname = 'psql-' + datetime.strftime(datetime.now(), "%Y-%m-%d-%H-%M") + '-UTC' + '.sql'
81 | message_succ = ("The backup was successfully created. \n"
82 | "The database dump name: " + dumpname)
83 | message_fail = ("The backup failed, please check logs.")
84 | succ_color = "#36ee33"
85 | fail_color = "#ee3f33"
86 |
87 | if backup_postgres_db(PG_HOST, PG_DATABASE, PG_PORT, PG_USER, PG_PASS, source_path + dumpname) != 1:
88 | if upload_to_s3(source_path + dumpname, AWS_BUCKET_NAME, dest_path + dumpname, AWS_BUCKET_REGION) != 1:
89 | send_slack_notification(SLACK_URL, message_succ, succ_color)
90 | else:
91 | send_slack_notification(SLACK_URL, message_fail, fail_color)
92 | else:
93 | send_slack_notification(SLACK_URL, message_fail, fail_color)
94 |
--------------------------------------------------------------------------------
/terraform/layer1-aws/outputs.tf:
--------------------------------------------------------------------------------
1 | # Common outputs
2 | output "name" {
3 | description = "Project name, required to form unique resource names"
4 | value = local.name
5 | }
6 |
7 | output "name_wo_region" {
8 | description = "Project name, required to form unique resource names without short region"
9 | value = local.name_wo_region
10 | }
11 |
12 | output "domain_name" {
13 | description = "Domain name"
14 | value = var.domain_name
15 | }
16 |
17 | output "env" {
18 | description = "Suffix for the hostname depending on workspace"
19 | value = local.env
20 | }
21 |
22 | output "route53_zone_id" {
23 | description = "ID of domain zone"
24 | value = local.zone_id
25 | }
26 |
27 | output "region" {
28 | description = "Target region for all infrastructure resources"
29 | value = var.region
30 | }
31 |
32 | output "short_region" {
33 | description = "The abbreviated name of the region, required to form unique resource names"
34 | value = local.short_region
35 | }
36 |
37 | output "az_count" {
38 | description = "Count of avaiablity zones, min 2"
39 | value = var.az_count
40 | }
41 |
42 | output "allowed_ips" {
43 | description = "List of allowed ip's, used for direct ssh access to instances."
44 | value = var.allowed_ips
45 | }
46 |
47 | output "vpc_name" {
48 | description = "Name of infra VPC"
49 | value = module.vpc.name
50 | }
51 |
52 | output "vpc_id" {
53 | description = "ID of infra VPC"
54 | value = module.vpc.vpc_id
55 | }
56 |
57 | output "vpc_cidr" {
58 | description = "CIDR block of infra VPC"
59 | value = var.cidr
60 | }
61 |
62 | output "vpc_public_subnets" {
63 | description = "Public subnets of infra VPC"
64 | value = module.vpc.public_subnets
65 | }
66 |
67 | output "vpc_private_subnets" {
68 | description = "Private subnets of infra VPC"
69 | value = module.vpc.private_subnets
70 | }
71 |
72 | output "vpc_database_subnets" {
73 | description = "Database subnets of infra VPC"
74 | value = module.vpc.database_subnets
75 | }
76 |
77 | output "vpc_intra_subnets" {
78 | description = "Private intra subnets "
79 | value = module.vpc.intra_subnets
80 | }
81 |
82 | output "eks_cluster_endpoint" {
83 | description = "Endpoint for EKS control plane."
84 | value = module.eks.cluster_endpoint
85 | }
86 |
87 | output "eks_cluster_security_group_id" {
88 | description = "Security group ids attached to the cluster control plane."
89 | value = module.eks.cluster_security_group_id
90 | }
91 |
92 | output "eks_kubectl_console_config" {
93 | value = "aws eks update-kubeconfig --name ${module.eks.cluster_name} --region ${var.region}"
94 | description = "description"
95 | depends_on = []
96 | }
97 |
98 | output "eks_cluster_id" {
99 | value = module.eks.cluster_name
100 | }
101 |
102 | output "eks_oidc_provider_arn" {
103 | description = "ARN of EKS oidc provider"
104 | value = module.eks.oidc_provider_arn
105 | }
106 |
107 | output "ssl_certificate_arn" {
108 | description = "ARN of SSL certificate"
109 | value = local.ssl_certificate_arn
110 | }
111 |
112 | output "node_group_default_iam_role_arn" {
113 | value = module.eks.self_managed_node_groups["default"].iam_role_arn
114 | }
115 |
116 | output "node_group_default_iam_role_name" {
117 | value = module.eks.self_managed_node_groups["default"].iam_role_name
118 | }
119 |
--------------------------------------------------------------------------------
/terraform/layer1-aws/aws-vpc.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | cidr_subnets = [for cidr_block in cidrsubnets(var.cidr, 2, 2, 2, 2) : cidrsubnets(cidr_block, 4, 4, 4, 4)]
3 | private_subnets = chunklist(local.cidr_subnets[0], var.az_count)[0]
4 | public_subnets = chunklist(local.cidr_subnets[1], var.az_count)[0]
5 | database_subnets = chunklist(local.cidr_subnets[2], var.az_count)[0]
6 | intra_subnets = chunklist(local.cidr_subnets[3], var.az_count)[0]
7 | azs = data.aws_availability_zones.available.names
8 | }
9 |
10 | # https://github.com/terraform-aws-modules/terraform-aws-vpc/blob/master/examples/complete-vpc/main.tf#L82
11 | data "aws_security_group" "default" {
12 | name = "default"
13 | vpc_id = module.vpc.vpc_id
14 | }
15 |
16 | #tfsec:ignore:aws-ec2-no-public-ip-subnet
17 | #tfsec:ignore:aws-ec2-require-vpc-flow-logs-for-all-vpcs
18 | module "vpc" {
19 | source = "terraform-aws-modules/vpc/aws"
20 | version = "4.0.1"
21 |
22 | name = local.name
23 | cidr = var.cidr
24 |
25 | azs = local.azs
26 | private_subnets = local.private_subnets
27 | public_subnets = local.public_subnets
28 | database_subnets = local.database_subnets
29 | intra_subnets = local.intra_subnets
30 |
31 | single_nat_gateway = var.single_nat_gateway
32 | enable_nat_gateway = true
33 | enable_vpn_gateway = false
34 | enable_dns_hostnames = true
35 | enable_dns_support = true
36 | map_public_ip_on_launch = true
37 |
38 | create_database_subnet_group = false
39 |
40 | manage_default_security_group = true
41 | default_security_group_ingress = []
42 | default_security_group_egress = []
43 |
44 | tags = merge(local.tags, {
45 | "kubernetes.io/cluster/${local.name}" = "shared"
46 | })
47 |
48 | private_subnet_tags = {
49 | Name = "${local.name}-private"
50 | destination = "private"
51 | "karpenter.sh/discovery" = "private"
52 | "kubernetes.io/role/internal-elb" = "1"
53 | }
54 |
55 | private_route_table_tags = {
56 | Name = "${local.name}-private"
57 | destination = "private"
58 | }
59 |
60 | public_subnet_tags = {
61 | Name = "${local.name}-public"
62 | destination = "public"
63 | "karpenter.sh/discovery" = "public"
64 | "kubernetes.io/role/elb" = "1"
65 | }
66 |
67 | public_route_table_tags = {
68 | Name = "${local.name}-public"
69 | destination = "public"
70 | }
71 |
72 | database_subnet_tags = {
73 | Name = "${local.name}-database"
74 | destination = "database"
75 | }
76 |
77 | database_route_table_tags = {
78 | Name = "${local.name}-database"
79 | destination = "database"
80 | }
81 |
82 | intra_subnet_tags = {
83 | Name = "${local.name}-intra"
84 | destination = "intra"
85 | }
86 |
87 | intra_route_table_tags = {
88 | Name = "${local.name}-intra"
89 | destination = "intra"
90 | }
91 | }
92 |
93 | module "vpc_gateway_endpoints" {
94 | source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
95 | version = "4.0.1"
96 |
97 | vpc_id = module.vpc.vpc_id
98 |
99 | endpoints = {
100 | s3 = {
101 | service = "s3"
102 | service_type = "Gateway"
103 | route_table_ids = flatten([
104 | module.vpc.intra_route_table_ids,
105 | module.vpc.private_route_table_ids,
106 | module.vpc.public_route_table_ids
107 | ])
108 | tags = {
109 | Name = "${local.name}-s3"
110 | }
111 | }
112 | }
113 |
114 | tags = local.tags
115 | }
116 |
--------------------------------------------------------------------------------
/CHANGELOG.previous.md:
--------------------------------------------------------------------------------
1 |
2 | ## [Unreleased]
3 |
4 |
5 |
6 | ## 1.0.0 - 2021-10-14
7 | ### HotFix
8 | - add allowed_account_ids varialbe to layer2
9 |
10 | ### Pull Requests
11 | - Merge pull request [#116](https://github.com/maddevsio/aws-eks-base/issues/116) from maddevsio/Feature/add_depends_on_eks_modify_readme
12 | - Merge pull request [#115](https://github.com/maddevsio/aws-eks-base/issues/115) from maddevsio/Feature/aws_eks_addon_depends_on
13 | - Merge pull request [#111](https://github.com/maddevsio/aws-eks-base/issues/111) from maddevsio/Feature/eks_depends_on_vpc
14 | - Merge pull request [#110](https://github.com/maddevsio/aws-eks-base/issues/110) from maddevsio/eks-addons
15 | - Merge pull request [#104](https://github.com/maddevsio/aws-eks-base/issues/104) from maddevsio/tfsec
16 | - Merge pull request [#93](https://github.com/maddevsio/aws-eks-base/issues/93) from maddevsio/feature/k8s-secrets-encryption
17 | - Merge pull request [#58](https://github.com/maddevsio/aws-eks-base/issues/58) from maddevsio/feature/pinned-terragrunt-version
18 | - Merge pull request [#59](https://github.com/maddevsio/aws-eks-base/issues/59) from maddevsio/feature/terraform-utils
19 | - Merge pull request [#55](https://github.com/maddevsio/aws-eks-base/issues/55) from maddevsio/fix/filebeat-configuration
20 | - Merge pull request [#56](https://github.com/maddevsio/aws-eks-base/issues/56) from maddevsio/fix/aws-iam-s3
21 | - Merge pull request [#53](https://github.com/maddevsio/aws-eks-base/issues/53) from maddevsio/feature/add-depends-on
22 | - Merge pull request [#51](https://github.com/maddevsio/aws-eks-base/issues/51) from maddevsio/feature/update-terraform-and-terraform-providers
23 | - Merge pull request [#50](https://github.com/maddevsio/aws-eks-base/issues/50) from maddevsio/feature/change-log-level
24 | - Merge pull request [#47](https://github.com/maddevsio/aws-eks-base/issues/47) from maddevsio/ebs_encryption
25 | - Merge pull request [#46](https://github.com/maddevsio/aws-eks-base/issues/46) from maddevsio/ebs_encryption
26 | - Merge pull request [#44](https://github.com/maddevsio/aws-eks-base/issues/44) from maddevsio/count_of_helm_releases
27 | - Merge pull request [#38](https://github.com/maddevsio/aws-eks-base/issues/38) from maddevsio/fix/prometheus-stack
28 | - Merge pull request [#29](https://github.com/maddevsio/aws-eks-base/issues/29) from maddevsio/feature/Add-github-actions-ci
29 | - Merge pull request [#33](https://github.com/maddevsio/aws-eks-base/issues/33) from AntonGrushkin/antongrushkin
30 | - Merge pull request [#31](https://github.com/maddevsio/aws-eks-base/issues/31) from maddevsio/feature/variables-cleanup
31 | - Merge pull request [#24](https://github.com/maddevsio/aws-eks-base/issues/24) from maddevsio/feature/license-badge
32 | - Merge pull request [#23](https://github.com/maddevsio/aws-eks-base/issues/23) from maddevsio/fix/ru-readme
33 | - Merge pull request [#21](https://github.com/maddevsio/aws-eks-base/issues/21) from maddevsio/fix/prom-template-error
34 | - Merge pull request [#20](https://github.com/maddevsio/aws-eks-base/issues/20) from maddevsio/feature/adv-of-the-boiler
35 | - Merge pull request [#17](https://github.com/maddevsio/aws-eks-base/issues/17) from maddevsio/fix/digram-fix
36 | - Merge pull request [#16](https://github.com/maddevsio/aws-eks-base/issues/16) from maddevsio/fix/analytics
37 | - Merge pull request [#15](https://github.com/maddevsio/aws-eks-base/issues/15) from maddevsio/feature/analytics
38 | - Merge pull request [#13](https://github.com/maddevsio/aws-eks-base/issues/13) from maddevsio/pritunl_efs
39 | - Merge pull request [#11](https://github.com/maddevsio/aws-eks-base/issues/11) from maddevsio/fix_variable_for_aws_iam_policy_document
40 | - Merge pull request [#12](https://github.com/maddevsio/aws-eks-base/issues/12) from maddevsio/Tools_for_cubectl
41 |
42 |
43 | [Unreleased]: https://github.com/maddevsio/aws-eks-base/compare/1.0.0...HEAD
44 |
--------------------------------------------------------------------------------
/terraform/layer2-k8s/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | default = "us-east-1"
4 | description = "Default infrastructure region"
5 | }
6 |
7 | variable "name" {
8 | description = "Project name, required to create unique resource names"
9 | }
10 |
11 | variable "environment" {
12 | default = "demo"
13 | description = "Env name"
14 | }
15 |
16 | variable "short_region" {
17 | description = "The abbreviated name of the region, required to form unique resource names"
18 | default = {
19 | us-east-1 = "use1" # US East (N. Virginia)
20 | us-east-2 = "use2" # US East (Ohio)
21 | us-west-1 = "usw1" # US West (N. California)
22 | us-west-2 = "usw2" # US West (Oregon)
23 | ap-east-1 = "ape1" # Asia Pacific (Hong Kong)
24 | ap-south-1 = "aps1" # Asia Pacific (Mumbai)
25 | ap-northeast-2 = "apn2" # Asia Pacific (Seoul)
26 | ap-northeast-1 = "apn1" # Asia Pacific (Tokyo)
27 | ap-southeast-1 = "apse1" # Asia Pacific (Singapore)
28 | ap-southeast-2 = "apse2" # Asia Pacific (Sydney)
29 | ca-central-1 = "cac1" # Canada (Central)
30 | cn-north-1 = "cnn1" # China (Beijing)
31 | cn-northwest-1 = "cnnw1" # China (Ningxia)
32 | eu-central-1 = "euc1" # EU (Frankfurt)
33 | eu-west-1 = "euw1" # EU (Ireland)
34 | eu-west-2 = "euw2" # EU (London)
35 | eu-west-3 = "euw3" # EU (Paris)
36 | eu-north-1 = "eun1" # EU (Stockholm)
37 | sa-east-1 = "sae1" # South America (Sao Paulo)
38 | us-gov-east-1 = "usge1" # AWS GovCloud (US-East)
39 | us-gov-west-1 = "usgw1" # AWS GovCloud (US)
40 | }
41 | }
42 |
43 | variable "domain_name" {
44 | description = "Main public domain name"
45 | }
46 |
47 | variable "zone_id" {
48 | default = null
49 | description = "R53 zone id for public domain"
50 | }
51 |
52 | variable "allowed_ips" {
53 | type = list(any)
54 | default = []
55 | description = "IP addresses allowed to connect to private resources"
56 | }
57 |
58 | variable "allowed_account_ids" {
59 | description = "List of allowed AWS account IDs"
60 | default = []
61 | }
62 |
63 | variable "additional_allowed_ips" {
64 | type = list(any)
65 | default = []
66 | description = "IP addresses allowed to connect to private resources"
67 | }
68 |
69 | variable "vpc_id" {
70 | description = "ID of infra VPC"
71 | }
72 |
73 | variable "vpc_cidr" {
74 | description = "Default CIDR block for VPC"
75 | default = "10.0.0.0/16"
76 | }
77 |
78 | variable "eks_cluster_id" {
79 | description = "ID of the created EKS cluster."
80 | }
81 |
82 | variable "eks_oidc_provider_arn" {
83 | description = "ARN of EKS oidc provider"
84 | }
85 |
86 | variable "ssl_certificate_arn" {
87 | description = "ARN of ACM SSL certificate"
88 | }
89 |
90 | variable "helm_release_history_size" {
91 | description = "How much helm releases to store"
92 | default = 5
93 | }
94 |
95 | variable "nginx_ingress_ssl_terminator" {
96 | description = "Select SSL termination type"
97 | default = "lb"
98 | # options:
99 | # lb - terminate ssl on loadbalancer side
100 | # nginx - terminate ssl on nginx side
101 | }
102 |
103 | # Cluster autoscaler
104 | variable "cluster_autoscaler_version" {
105 | description = "Version of cluster autoscaler"
106 | default = "v1.25.0"
107 | }
108 |
109 |
110 | variable "helm_charts_path" {
111 | type = string
112 | description = "where to find the helm charts"
113 | default = "../../helm-charts/"
114 | }
115 |
116 | variable "node_group_default_iam_role_arn" {
117 | description = "The IAM Role ARN of a default nodegroup"
118 | default = ""
119 | }
120 |
121 | variable "node_group_default_iam_role_name" {
122 | description = "The IAM Role name of a default nodegroup"
123 | default = ""
124 | }
125 |
--------------------------------------------------------------------------------
/terraform/layer2-k8s/eks-external-dns.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | external_dns = {
3 | name = local.helm_releases[index(local.helm_releases.*.id, "external-dns")].id
4 | enabled = local.helm_releases[index(local.helm_releases.*.id, "external-dns")].enabled
5 | chart = local.helm_releases[index(local.helm_releases.*.id, "external-dns")].chart
6 | repository = local.helm_releases[index(local.helm_releases.*.id, "external-dns")].repository
7 | chart_version = local.helm_releases[index(local.helm_releases.*.id, "external-dns")].chart_version
8 | namespace = local.helm_releases[index(local.helm_releases.*.id, "external-dns")].namespace
9 | }
10 | external_dns_values = < 0 ? length(var.network_policies) : 0
3 |
4 | metadata {
5 | name = var.network_policies[count.index].name
6 | namespace = kubernetes_namespace.this[0].id
7 | }
8 | spec {
9 | dynamic "pod_selector" {
10 | for_each = lookup(var.network_policies[count.index], "pod_selector", null) != null ? [var.network_policies[count.index].pod_selector] : []
11 | content {
12 | dynamic "match_expressions" {
13 | for_each = lookup(pod_selector.value, "match_expressions", null) != null ? [pod_selector.value.match_expressions] : []
14 | content {
15 | key = lookup(match_expressions.value, "key", null)
16 | operator = lookup(match_expressions.value, "operator", null)
17 | values = lookup(match_expressions.value, "values", null)
18 | }
19 | }
20 | match_labels = lookup(pod_selector.value, "match_labels", null)
21 | }
22 | }
23 |
24 | dynamic "ingress" {
25 | for_each = lookup(var.network_policies[count.index], "ingress", null) != null ? [var.network_policies[count.index].ingress] : []
26 | content {
27 | dynamic "from" {
28 | for_each = lookup(ingress.value, "from", null) != null ? ingress.value.from : []
29 | content {
30 |
31 | dynamic "namespace_selector" {
32 | for_each = lookup(from.value, "namespace_selector", null) != null ? [from.value.namespace_selector] : []
33 | content {
34 | match_labels = lookup(namespace_selector.value, "match_labels", null)
35 | dynamic "match_expressions" {
36 | for_each = lookup(namespace_selector.value, "match_expressions", null) != null ? [namespace_selector.value.match_expressions] : []
37 | content {
38 | key = lookup(match_expressions.value, "key", null)
39 | operator = lookup(match_expressions.value, "operator", null)
40 | values = lookup(match_expressions.value, "values", null)
41 | }
42 | }
43 | }
44 | }
45 |
46 | dynamic "pod_selector" {
47 | for_each = lookup(from.value, "pod_selector", null) != null ? [from.value.pod_selector] : []
48 | content {
49 | match_labels = lookup(pod_selector.value, "match_labels", null)
50 | dynamic "match_expressions" {
51 | for_each = lookup(pod_selector.value, "match_expressions", null) != null ? [pod_selector.value.match_expressions] : []
52 | content {
53 | key = lookup(match_expressions.value, "key", null)
54 | operator = lookup(match_expressions.value, "operator", null)
55 | values = lookup(match_expressions.value, "values", null)
56 | }
57 | }
58 | }
59 | }
60 |
61 | dynamic "ip_block" {
62 | for_each = lookup(from.value, "ip_block", null) != null ? [from.value.ip_block] : []
63 | content {
64 | cidr = lookup(ip_block.value, "cidr", null)
65 | except = lookup(ip_block.value, "except", null)
66 | }
67 | }
68 |
69 | }
70 | }
71 |
72 | dynamic "ports" {
73 | for_each = lookup(ingress.value, "ports", null) != null ? ingress.value.ports : []
74 | content {
75 | port = ports.value.port
76 | protocol = ports.value.protocol
77 | }
78 | }
79 |
80 | }
81 | }
82 |
83 | dynamic "egress" {
84 | for_each = lookup(var.network_policies[count.index], "egress", null) != null ? [var.network_policies[count.index].egress] : []
85 | content {
86 | dynamic "to" {
87 | for_each = lookup(egress.value, "to", null) != null ? egress.value.to : []
88 | content {
89 |
90 | dynamic "namespace_selector" {
91 | for_each = lookup(to.value, "namespace_selector", null) != null ? [to.value.namespace_selector] : []
92 | content {
93 | match_labels = lookup(namespace_selector.value, "match_labels", null)
94 | dynamic "match_expressions" {
95 | for_each = lookup(namespace_selector.value, "match_expressions", null) != null ? [namespace_selector.value.match_expressions] : []
96 | content {
97 | key = lookup(match_expressions.value, "key", null)
98 | operator = lookup(match_expressions.value, "operator", null)
99 | values = lookup(match_expressions.value, "values", null)
100 | }
101 | }
102 | }
103 | }
104 |
105 | dynamic "pod_selector" {
106 | for_each = lookup(to.value, "pod_selector", null) != null ? [to.value.pod_selector] : []
107 | content {
108 | match_labels = lookup(pod_selector.value, "match_labels", null)
109 | dynamic "match_expressions" {
110 | for_each = lookup(pod_selector.value, "match_expressions", null) != null ? [pod_selector.value.match_expressions] : []
111 | content {
112 | key = lookup(match_expressions.value, "key", null)
113 | operator = lookup(match_expressions.value, "operator", null)
114 | values = lookup(match_expressions.value, "values", null)
115 | }
116 | }
117 | }
118 | }
119 |
120 | dynamic "ip_block" {
121 | for_each = lookup(to.value, "ip_block", null) != null ? [to.value.ip_block] : []
122 | content {
123 | cidr = lookup(ip_block.value, "cidr", null)
124 | except = lookup(ip_block.value, "except", null)
125 | }
126 | }
127 |
128 | }
129 | }
130 |
131 | dynamic "ports" {
132 | for_each = lookup(egress.value, "ports", null) != null ? egress.value.ports : []
133 | content {
134 | port = ports.value.port
135 | protocol = ports.value.protocol
136 | }
137 | }
138 |
139 | }
140 | }
141 |
142 | policy_types = lookup(var.network_policies[count.index], "policy_types", ["Ingress", "Egress"])
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/terraform/layer2-k8s/eks-ingress-nginx-controller.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | ingress_nginx = {
3 | name = local.helm_releases[index(local.helm_releases.*.id, "ingress-nginx")].id
4 | enabled = local.helm_releases[index(local.helm_releases.*.id, "ingress-nginx")].enabled
5 | chart = local.helm_releases[index(local.helm_releases.*.id, "ingress-nginx")].chart
6 | repository = local.helm_releases[index(local.helm_releases.*.id, "ingress-nginx")].repository
7 | chart_version = local.helm_releases[index(local.helm_releases.*.id, "ingress-nginx")].chart_version
8 | namespace = local.helm_releases[index(local.helm_releases.*.id, "ingress-nginx")].namespace
9 | }
10 | ingress_nginx_general_values = <