├── terraform ├── layer2-k8s │ ├── outputs.tf │ ├── eks-fargate.tf │ ├── aws-sm-secrets.tf │ ├── demo.tfvars.example │ ├── eks-storageclass.tf │ ├── main.tf │ ├── providers.tf │ ├── locals.tf │ ├── eks-reloader.tf │ ├── eks-prometheus-operator-crds.tf │ ├── eks-keda.tf │ ├── helm-releases.yaml │ ├── variables.tf │ ├── eks-external-dns.tf │ ├── eks-external-secrets.tf │ ├── eks-loki-stack.tf │ ├── eks-ingress-nginx-controller.tf │ ├── eks-cert-manager.tf │ ├── eks-gitlab-runner.tf │ └── eks-karpenter.tf ├── .terraform-version ├── modules │ ├── aws-wafv2-top-10-owasp-rules │ │ ├── outputs.tf │ │ ├── README.md │ │ └── variables.tf │ ├── aws-iam-eks-trusted │ │ ├── outputs.tf │ │ ├── variables.tf │ │ ├── main.tf │ │ └── README.md │ ├── aws-pritunl │ │ ├── output.tf │ │ ├── ami.tf │ │ ├── backup.tf │ │ ├── efs.tf │ │ ├── security_groups.tf │ │ ├── variables.tf │ │ ├── templates │ │ │ └── user-data.sh │ │ ├── main.tf │ │ └── iam.tf │ ├── aws-cost-allocation-tags │ │ ├── variables.tf │ │ ├── main.tf │ │ └── README.md │ ├── aws-iam-user-with-policy │ │ ├── variables.tf │ │ ├── iam-user.tf │ │ ├── outputs.tf │ │ └── README.md │ ├── eks-kubernetes-namespace │ │ ├── output.tf │ │ ├── main.tf │ │ ├── limitrange.tf │ │ ├── resourcequota.tf │ │ ├── variables.tf │ │ ├── README.md │ │ └── network-policy.tf │ └── self-signed-certificate │ │ ├── outputs.tf │ │ ├── data-sources │ │ ├── p8.sh │ │ └── pfx.sh │ │ ├── variables.tf │ │ ├── main.tf │ │ └── README.md └── layer1-aws │ ├── demo.tfvars.example │ ├── aws-r53.tf │ ├── aws-acm.tf │ ├── providers.tf │ ├── locals.tf │ ├── aws-pritunl.tf │ ├── main.tf │ ├── aws-cloudtrail.tf │ ├── outputs.tf │ ├── aws-vpc.tf │ ├── aws-eks.tf │ ├── .terraform.lock.hcl │ └── variables.tf ├── terragrunt ├── .terraform-version ├── .terragrunt-version ├── demo │ ├── region.yaml │ └── us-east-1 │ │ ├── env.hcl │ │ ├── env.yaml │ │ ├── aws-base │ │ ├── terragrunt.hcl │ │ └── .terraform.lock.hcl │ │ └── k8s-addons │ │ └── terragrunt.hcl └── terragrunt.hcl ├── helm-charts ├── certificate │ ├── .helmignore │ ├── values.yaml │ ├── Chart.yaml │ └── templates │ │ └── certificate.yaml ├── cluster-issuer │ ├── .helmignore │ ├── values.yaml │ ├── Chart.yaml │ └── templates │ │ ├── cluster-issuer-prod.yaml │ │ └── cluster-issuer-stage.yaml ├── elk │ ├── charts │ │ ├── kibana-7.16.2.tgz │ │ ├── filebeat-7.16.2.tgz │ │ ├── logstash-7.16.2.tgz │ │ ├── apm-server-7.16.2.tgz │ │ ├── metricbeat-7.16.2.tgz │ │ └── elasticsearch-7.16.2.tgz │ ├── Chart.yaml │ ├── .helmignore │ ├── requirements.lock │ ├── values.yaml │ ├── requirements.yaml │ └── templates │ │ └── _helpers.tpl ├── pg-exporter-user │ ├── Chart.yaml │ ├── values.yaml │ ├── .helmignore │ └── templates │ │ ├── job.yaml │ │ └── _helpers.tpl └── postgresql-backups │ ├── Chart.yaml │ ├── templates │ ├── externalsecret.yaml │ ├── scheduler.yaml │ └── _helpers.tpl │ ├── .helmignore │ └── values.yaml ├── docker ├── postgresql-backups │ ├── requirements.txt │ ├── Dockerfile │ ├── README.md │ └── backup.py ├── elasticsearch │ └── Dockerfile ├── postgresql-exporter-script │ ├── Dockerfile │ ├── README.md │ └── pg_exporter_user.sql ├── wordpress │ ├── Dockerfile │ ├── remoteip.conf │ ├── .htaccess │ └── status.conf ├── terraform-utils │ └── Dockerfile └── aws-eks-utils │ └── Dockerfile ├── .editorconfig ├── .pre-commit-config.yaml ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── aws-eks-utils-image.yml │ ├── terraform-utils-image.yml │ └── terraform-ci.yml ├── ISSUE_TEMPLATE.md └── semantic.yml ├── .chglog ├── config.yml └── CHANGELOG.tpl.md ├── .gitlab-ci.yml ├── examples ├── echoserver-deployment.yaml ├── wordpress-deployment-external-secrets.yml └── wordpress-deployment.yml ├── .gitignore └── CHANGELOG.previous.md /terraform/layer2-k8s/outputs.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /terraform/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.4.4 2 | -------------------------------------------------------------------------------- /terragrunt/.terraform-version: -------------------------------------------------------------------------------- 1 | 1.4.4 2 | -------------------------------------------------------------------------------- /terragrunt/.terragrunt-version: -------------------------------------------------------------------------------- 1 | 0.45.0 2 | -------------------------------------------------------------------------------- /terragrunt/demo/region.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | region: us-east-1 3 | -------------------------------------------------------------------------------- /helm-charts/certificate/.helmignore: -------------------------------------------------------------------------------- 1 | tests/ 2 | .pytest_cache/ 3 | -------------------------------------------------------------------------------- /helm-charts/cluster-issuer/.helmignore: -------------------------------------------------------------------------------- 1 | tests/ 2 | .pytest_cache/ 3 | -------------------------------------------------------------------------------- /helm-charts/cluster-issuer/values.yaml: -------------------------------------------------------------------------------- 1 | dnsZone: 2 | dnsZoneId: 3 | region: 4 | email: -------------------------------------------------------------------------------- /helm-charts/certificate/values.yaml: -------------------------------------------------------------------------------- 1 | domainName: "*.example.com" 2 | commonName: "example.com" 3 | -------------------------------------------------------------------------------- /docker/postgresql-backups/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3==1.16.25 2 | botocore==1.19.25 3 | requests==2.22.0 4 | 5 | -------------------------------------------------------------------------------- /helm-charts/elk/charts/kibana-7.16.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddevsio/aws-eks-base/HEAD/helm-charts/elk/charts/kibana-7.16.2.tgz -------------------------------------------------------------------------------- /helm-charts/elk/charts/filebeat-7.16.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddevsio/aws-eks-base/HEAD/helm-charts/elk/charts/filebeat-7.16.2.tgz -------------------------------------------------------------------------------- /helm-charts/elk/charts/logstash-7.16.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddevsio/aws-eks-base/HEAD/helm-charts/elk/charts/logstash-7.16.2.tgz -------------------------------------------------------------------------------- /helm-charts/elk/charts/apm-server-7.16.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddevsio/aws-eks-base/HEAD/helm-charts/elk/charts/apm-server-7.16.2.tgz -------------------------------------------------------------------------------- /helm-charts/elk/charts/metricbeat-7.16.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddevsio/aws-eks-base/HEAD/helm-charts/elk/charts/metricbeat-7.16.2.tgz -------------------------------------------------------------------------------- /helm-charts/elk/charts/elasticsearch-7.16.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddevsio/aws-eks-base/HEAD/helm-charts/elk/charts/elasticsearch-7.16.2.tgz -------------------------------------------------------------------------------- /terraform/modules/aws-wafv2-top-10-owasp-rules/outputs.tf: -------------------------------------------------------------------------------- 1 | output "rule_group_arn" { 2 | value = aws_wafv2_rule_group.owasp_top10_rules.arn 3 | } 4 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-eks-trusted/outputs.tf: -------------------------------------------------------------------------------- 1 | output "role_arn" { 2 | description = "This role ARN" 3 | value = aws_iam_role.this.arn 4 | } 5 | -------------------------------------------------------------------------------- /helm-charts/certificate/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: Helm chart for service resources 3 | name: wildcard cert 4 | version: 0.0.1 5 | appVersion: 0.0.1 6 | -------------------------------------------------------------------------------- /helm-charts/cluster-issuer/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: Helm chart for service resources 3 | name: cluster-issuer 4 | version: 0.0.1 5 | appVersion: 0.0.1 6 | -------------------------------------------------------------------------------- /docker/elasticsearch/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.elastic.co/elasticsearch/elasticsearch:7.16.2 2 | RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install --batch repository-s3 3 | -------------------------------------------------------------------------------- /docker/postgresql-exporter-script/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/postgres:12-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY pg_exporter_user.sql /app/ 6 | 7 | CMD ["/bin/bash"] 8 | -------------------------------------------------------------------------------- /docker/wordpress/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM wordpress:5.4.2-apache 2 | 3 | COPY remoteip.conf /etc/apache2/conf-enabled/ 4 | COPY status.conf /etc/apache2/mods-available/ 5 | COPY .htaccess /var/www/html/ -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/output.tf: -------------------------------------------------------------------------------- 1 | output "pritunl_endpoint" { 2 | value = aws_eip.this.public_ip 3 | } 4 | output "pritunl_security_group" { 5 | value = module.ec2_sg.security_group_id 6 | } 7 | -------------------------------------------------------------------------------- /helm-charts/pg-exporter-user/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: pg-exporter-user 3 | description: A Helm chart for Kubernetes 4 | 5 | type: application 6 | 7 | version: 1.0.0 8 | 9 | appVersion: 1.0.0 10 | -------------------------------------------------------------------------------- /terragrunt/demo/us-east-1/env.hcl: -------------------------------------------------------------------------------- 1 | locals { 2 | values = merge( 3 | yamldecode(file(find_in_parent_folders("region.yaml"))), 4 | yamldecode(file("env.yaml")) 5 | ) 6 | } 7 | 8 | inputs = local.values 9 | -------------------------------------------------------------------------------- /helm-charts/postgresql-backups/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: postgresql-backups 3 | description: A Helm chart for Kubernetes 4 | 5 | type: application 6 | 7 | version: 1.0.0 8 | 9 | appVersion: 1.0.0 10 | -------------------------------------------------------------------------------- /terragrunt/demo/us-east-1/env.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name : "maddevs" 3 | domain_name: "maddevs.org" 4 | environment: "demo" 5 | 6 | az_count : 3 7 | allowed_ips: 8 | - "0.0.0.0/0" 9 | 10 | single_nat_gateway: true 11 | -------------------------------------------------------------------------------- /terraform/modules/aws-cost-allocation-tags/variables.tf: -------------------------------------------------------------------------------- 1 | variable "tags" { 2 | type = list(object({ 3 | tag_key = string 4 | status = string 5 | })) 6 | description = "A list of tags to use for cost allocation tags" 7 | } 8 | -------------------------------------------------------------------------------- /helm-charts/elk/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: elastic-stack 2 | version: 0.1.0 3 | appVersion: 7.16.2 4 | description: Elasticsearch stack 5 | keywords: 6 | - elasticsearch 7 | - filebeat 8 | - kibana 9 | - logstash 10 | - metricbeat 11 | - apm 12 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/eks-fargate.tf: -------------------------------------------------------------------------------- 1 | # Calico is not supported when using Fargate with Amazon EKS (NetworkPolicies won't work) 2 | module "fargate_namespace" { 3 | source = "../modules/eks-kubernetes-namespace" 4 | name = "fargate" 5 | } 6 | -------------------------------------------------------------------------------- /terraform/modules/aws-cost-allocation-tags/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_ce_cost_allocation_tag" "this" { 2 | for_each = { for item in var.tags : item.tag_key => item } 3 | 4 | tag_key = each.value.tag_key 5 | status = each.value.status 6 | } 7 | -------------------------------------------------------------------------------- /docker/wordpress/remoteip.conf: -------------------------------------------------------------------------------- 1 | RemoteIPHeader X-Forwarded-For 2 | RemoteIPTrustedProxy 10.0.0.0/8 3 | RemoteIPTrustedProxy 172.16.0.0/12 4 | RemoteIPTrustedProxy 192.168.0.0/16 5 | RemoteIPTrustedProxy 169.254.0.0/16 6 | RemoteIPTrustedProxy 127.0.0.0/8 7 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-user-with-policy/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "Project name, required to form unique resource names" 3 | } 4 | 5 | variable "policy" { 6 | description = "IAM policy that will be attached to user" 7 | } 8 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/aws-sm-secrets.tf: -------------------------------------------------------------------------------- 1 | data "aws_secretsmanager_secret" "infra" { 2 | name = "/${local.name_wo_region}/infra/layer2-k8s" 3 | } 4 | 5 | data "aws_secretsmanager_secret_version" "infra" { 6 | secret_id = data.aws_secretsmanager_secret.infra.id 7 | } 8 | -------------------------------------------------------------------------------- /helm-charts/pg-exporter-user/values.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repository: dymokd/pg-exporter-user 3 | tag: latest 4 | pullPolicy: IfNotPresent 5 | 6 | ttlSecondsAfterFinished: 0 7 | activeDeadlineSeconds: 3600 8 | backoffLimit: 6 9 | 10 | Envs: {} 11 | 12 | command: [] 13 | 14 | args: [] 15 | 16 | -------------------------------------------------------------------------------- /docker/wordpress/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteBase / 4 | RewriteRule ^index\.php$ - [L] 5 | RewriteCond %{REQUEST_FILENAME} !-f 6 | RewriteCond %{REQUEST_FILENAME} !-d 7 | RewriteCond %{REQUEST_URI} !=/server-status 8 | RewriteRule . /index.php [L] 9 | 10 | -------------------------------------------------------------------------------- /docker/wordpress/status.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SetHandler server-status 5 | Require local 6 | Require ip 10.0.0.0/16 7 | 8 | 9 | ExtendedStatus On 10 | 11 | 12 | ProxyStatus On 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/ami.tf: -------------------------------------------------------------------------------- 1 | data "aws_ami" "amazon_linux_2" { 2 | most_recent = true 3 | owners = ["amazon"] 4 | 5 | 6 | filter { 7 | name = "virtualization-type" 8 | values = ["hvm"] 9 | } 10 | 11 | filter { 12 | name = "name" 13 | values = ["amzn2-ami-hvm-*-x86_64-gp2"] 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /helm-charts/certificate/templates/certificate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Certificate 3 | metadata: 4 | name: nginx-tls 5 | spec: 6 | secretName: nginx-tls 7 | issuerRef: 8 | name: letsencrypt-prod 9 | kind: ClusterIssuer 10 | dnsNames: 11 | - {{ .Values.domainName | quote }} 12 | - {{ .Values.commonName | quote }} 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | tab_width = 2 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | 12 | [*.{txt,go}] 13 | indent_style = tab 14 | indent_size = 4 15 | tab_width = 4 16 | 17 | [*.{diff,md}] 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-user-with-policy/iam-user.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_user" "this_user" { 2 | name = var.name 3 | } 4 | 5 | resource "aws_iam_access_key" "this_user" { 6 | user = aws_iam_user.this_user.name 7 | } 8 | 9 | resource "aws_iam_user_policy" "this" { 10 | name = var.name 11 | user = aws_iam_user.this_user.name 12 | 13 | policy = var.policy 14 | } 15 | -------------------------------------------------------------------------------- /terraform/modules/eks-kubernetes-namespace/output.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | value = kubernetes_namespace.this[0].metadata[0].name 3 | description = "The name of the created namespace (from object metadata)" 4 | } 5 | 6 | output "labels_name" { 7 | value = kubernetes_namespace.this[0].metadata[0].labels.name 8 | description = "The value of the name label" 9 | } 10 | -------------------------------------------------------------------------------- /terraform/modules/self-signed-certificate/outputs.tf: -------------------------------------------------------------------------------- 1 | output "private_key_pem" { 2 | value = tls_private_key.this.private_key_pem 3 | description = "" 4 | } 5 | 6 | output "cert_pem" { 7 | value = tls_self_signed_cert.this.cert_pem 8 | description = "" 9 | } 10 | 11 | output "p8" { 12 | value = data.external.this_p8.result["p8"] 13 | description = "" 14 | } 15 | -------------------------------------------------------------------------------- /terraform/modules/self-signed-certificate/data-sources/p8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu -o pipefail 3 | 4 | eval "$(jq -r '@sh "export PRIVATE_KEY_PEM=\(.private_key_pem)"')" 5 | 6 | file="$(mktemp)" 7 | trap 'rm -f $file' EXIT 8 | 9 | echo "${PRIVATE_KEY_PEM}" > "$file" 10 | 11 | P8="$(openssl pkcs8 \ 12 | -in "$file" \ 13 | -topk8 \ 14 | -nocrypt)" 15 | 16 | jq -n --arg p8 "$P8" '{"p8":$p8}' 17 | -------------------------------------------------------------------------------- /terragrunt/demo/us-east-1/aws-base/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | include "root" { 2 | path = find_in_parent_folders() 3 | expose = true 4 | merge_strategy = "deep" 5 | } 6 | 7 | include "env" { 8 | path = find_in_parent_folders("env.hcl") 9 | expose = true 10 | merge_strategy = "deep" 11 | } 12 | 13 | terraform { 14 | source = "${get_terragrunt_dir()}/../../../../terraform//layer1-aws" 15 | } 16 | -------------------------------------------------------------------------------- /terraform/layer1-aws/demo.tfvars.example: -------------------------------------------------------------------------------- 1 | ########## 2 | # Common 3 | ########## 4 | name = "example" 5 | domain_name = "example.org" 6 | environment = "demo" 7 | 8 | ########## 9 | # Network 10 | ########## 11 | region = "us-east-1" 12 | az_count = 3 13 | allowed_ips = [ 14 | "0.0.0.0/0" 15 | ] 16 | single_nat_gateway = true 17 | 18 | ########## 19 | # EKS 20 | ########## 21 | eks_cluster_encryption_config_enable = true 22 | -------------------------------------------------------------------------------- /helm-charts/postgresql-backups/templates/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ExternalSecret.enabled -}} 2 | apiVersion: 'kubernetes-client.io/v1' 3 | kind: ExternalSecret 4 | metadata: 5 | name: {{ include "postgresql-backups.fullname" . }} 6 | spec: 7 | backendType: systemManager 8 | data: 9 | {{- if .Values.ExternalSecret.Envs }} 10 | {{ toYaml .Values.ExternalSecret.Envs | nindent 12 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/demo.tfvars.example: -------------------------------------------------------------------------------- 1 | ########## 2 | # Common 3 | ########## 4 | name = "example" 5 | environment = "demo" 6 | domain_name = "example.org" 7 | zone_id = 8 | 9 | ssl_certificate_arn = 10 | 11 | ########## 12 | # Network 13 | ########## 14 | region = "us-east-1" 15 | vpc_id = 16 | vpc_cidr = 17 | 18 | allowed_ips = [ 19 | "0.0.0.0/0" 20 | ] 21 | 22 | eks_cluster_id = 23 | eks_oidc_provider_arn = 24 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-eks-trusted/variables.tf: -------------------------------------------------------------------------------- 1 | variable "oidc_provider_arn" { 2 | description = "The ARN of the OIDC Provider" 3 | } 4 | 5 | variable "name" { 6 | description = "Name, required to form unique resource names" 7 | } 8 | 9 | variable "region" { 10 | description = "Target region for all infrastructure resources" 11 | } 12 | 13 | variable "policy" { 14 | description = "The policy that will be attached to role" 15 | } 16 | -------------------------------------------------------------------------------- /helm-charts/elk/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-user-with-policy/outputs.tf: -------------------------------------------------------------------------------- 1 | 2 | output "access_key_id" { 3 | value = aws_iam_access_key.this_user.id 4 | sensitive = true 5 | description = "AWS ACCESS_KEY_ID" 6 | depends_on = [aws_iam_access_key.this_user] 7 | } 8 | 9 | output "access_secret_key" { 10 | value = aws_iam_access_key.this_user.secret 11 | sensitive = true 12 | description = "AWS ACCESS_SECRET_KEY" 13 | depends_on = [aws_iam_access_key.this_user] 14 | } 15 | -------------------------------------------------------------------------------- /helm-charts/pg-exporter-user/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /helm-charts/postgresql-backups/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.76.0 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_docs 7 | - id: terragrunt_fmt 8 | # - id: terraform_tflint 9 | # - id: terraform_tfsec 10 | - repo: https://github.com/pre-commit/pre-commit-hooks 11 | rev: v4.3.0 12 | hooks: 13 | - id: check-merge-conflict 14 | - id: trailing-whitespace 15 | - id: detect-aws-credentials 16 | - id: detect-private-key 17 | -------------------------------------------------------------------------------- /docker/postgresql-exporter-script/README.md: -------------------------------------------------------------------------------- 1 | # Base image for postgresql-backups 2 | 3 | * This docker image contains the sql script for creating user with access to pg_stat_activity and pg_stat_replication 4 | 5 | # Build and push docker image 6 | 7 | * Build docker image 8 | 9 | ```yaml 10 | docker build -t pg-exporter-user . 11 | ``` 12 | 13 | ```yaml 14 | docker tag pg-exporter-user ecr-repository-url 15 | ``` 16 | 17 | ```yaml 18 | docker push ecr-repository-url 19 | ``` 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/eks-storageclass.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_storage_class" "advanced" { 2 | metadata { 3 | name = "advanced" 4 | } 5 | storage_provisioner = "kubernetes.io/aws-ebs" 6 | reclaim_policy = "Retain" 7 | allow_volume_expansion = true 8 | volume_binding_mode = "WaitForFirstConsumer" 9 | parameters = { 10 | type = "gp2" 11 | fsType = "ext4" 12 | encrypted = "true" # It is set to true for cases when global EBS encryption is disabled. 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /terraform/layer1-aws/aws-r53.tf: -------------------------------------------------------------------------------- 1 | data "aws_route53_zone" "main" { 2 | count = var.create_r53_zone && var.zone_id == null ? 0 : 1 3 | 4 | name = "${var.domain_name}." 5 | private_zone = false 6 | } 7 | 8 | module "r53_zone" { 9 | source = "terraform-aws-modules/route53/aws//modules/zones" 10 | version = "2.10.2" 11 | 12 | create = var.create_r53_zone 13 | 14 | zones = { 15 | (var.domain_name) = { 16 | comment = var.domain_name 17 | tags = local.tags 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /helm-charts/postgresql-backups/values.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repository: dymokd/pg-backups-s3 3 | tag: latest 4 | pullPolicy: IfNotPresent 5 | 6 | ExternalSecret: 7 | enabled: false 8 | Envs: {} 9 | 10 | scheduler: 11 | enabled: false 12 | schedule: "0 4 25 * *" 13 | resources: 14 | limits: 15 | cpu: 100m 16 | memory: 256Mi 17 | requests: 18 | cpu: 100m 19 | memory: 256Mi 20 | successfulJobsHistoryLimit: 5 21 | concurrencyPolicy: Forbid 22 | failedJobsHistoryLimit: 5 23 | restartPolicy: OnFailure 24 | 25 | -------------------------------------------------------------------------------- /terraform/modules/self-signed-certificate/data-sources/pfx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu -o pipefail 3 | 4 | export certificate_pem 5 | export private_key_pem 6 | 7 | eval "$(jq -r '@sh "certificate_pem=\(.certificate_pem) private_key_pem=\(.private_key_pem)"')" 8 | 9 | cert_file="$(mktemp)" 10 | trap 'rm -f $cert_file' EXIT 11 | 12 | echo "${certificate_pem}${private_key_pem}" >"$cert_file" 13 | 14 | pfx="$(openssl pkcs12 \ 15 | -in "$cert_file" \ 16 | -export \ 17 | -password "pass:" \ 18 | |base64 -)" 19 | 20 | jq -n --arg pfx "$pfx" '{"pfx":$pfx}' 21 | -------------------------------------------------------------------------------- /helm-charts/cluster-issuer/templates/cluster-issuer-prod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-prod 5 | spec: 6 | acme: 7 | server: https://acme-v02.api.letsencrypt.org/directory 8 | email: {{ .Values.email }} 9 | privateKeySecretRef: 10 | name: letsencrypt-prod 11 | solvers: 12 | - selector: 13 | dnsZones: 14 | - "{{ .Values.dnsZone }}" 15 | dns01: 16 | route53: 17 | region: {{ .Values.region }} 18 | hostedZoneID: {{ .Values.dnsZoneId }} 19 | -------------------------------------------------------------------------------- /terraform/modules/eks-kubernetes-namespace/main.tf: -------------------------------------------------------------------------------- 1 | # automatically add name to labels, 2 | # if it is not set 3 | locals { 4 | labels = merge({ 5 | name = var.name 6 | }, var.labels) 7 | } 8 | 9 | resource "kubernetes_namespace" "this" { 10 | # option to disable namespace creation 11 | # e.g. if you want to create namespace only in specific environment 12 | count = var.enable ? 1 : 0 13 | 14 | metadata { 15 | annotations = var.annotations 16 | labels = local.labels 17 | name = var.name 18 | } 19 | 20 | depends_on = [var.depends] 21 | } 22 | -------------------------------------------------------------------------------- /helm-charts/cluster-issuer/templates/cluster-issuer-stage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-staging 5 | spec: 6 | acme: 7 | server: https://acme-staging-v02.api.letsencrypt.org/directory 8 | email: {{ .Values.email }} 9 | privateKeySecretRef: 10 | name: letsencrypt-staging 11 | solvers: 12 | - selector: 13 | dnsZones: 14 | - "{{ .Values.dnsZone }}" 15 | dns01: 16 | route53: 17 | region: {{ .Values.region }} 18 | hostedZoneID: {{ .Values.dnsZoneId }} 19 | -------------------------------------------------------------------------------- /terraform/layer1-aws/aws-acm.tf: -------------------------------------------------------------------------------- 1 | data "aws_acm_certificate" "main" { 2 | count = var.create_acm_certificate ? 0 : 1 3 | 4 | domain = var.domain_name 5 | statuses = [ 6 | "ISSUED", 7 | "PENDING_VALIDATION"] 8 | most_recent = true 9 | } 10 | 11 | module "acm" { 12 | source = "terraform-aws-modules/acm/aws" 13 | version = "4.3.2" 14 | 15 | create_certificate = var.create_acm_certificate 16 | 17 | domain_name = local.domain_name 18 | zone_id = local.zone_id 19 | subject_alternative_names = [ 20 | "*.${local.domain_name}"] 21 | 22 | tags = local.tags 23 | } 24 | -------------------------------------------------------------------------------- /docker/terraform-utils/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/alpine:3.15.4 2 | ARG TERRAFORM_VERSION="1.1.8" 3 | 4 | WORKDIR /tmp 5 | 6 | #Install tfenv for terraform 7 | RUN apk add --update --no-cache openssl git bash curl unzip sudo && \ 8 | git clone https://github.com/tfutils/tfenv.git /usr/bin/.tfenv && \ 9 | ln -s /usr/bin/.tfenv/bin/* /usr/bin && \ 10 | chmod +x /usr/bin/tfenv 11 | 12 | #Install terraform 13 | RUN tfenv install $TERRAFORM_VERSION 14 | 15 | #Install tflint 16 | RUN curl https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash 17 | 18 | ENTRYPOINT [""] 19 | -------------------------------------------------------------------------------- /terraform/layer1-aws/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | allowed_account_ids = var.allowed_account_ids 4 | default_tags { 5 | tags = { 6 | Name = local.name 7 | Environment = local.env 8 | Terraform = "true" 9 | } 10 | } 11 | } 12 | 13 | provider "kubernetes" { 14 | host = module.eks.cluster_endpoint 15 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) 16 | token = data.aws_eks_cluster_auth.main.token 17 | } 18 | 19 | data "aws_eks_cluster_auth" "main" { 20 | name = module.eks.cluster_name 21 | } 22 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.4.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "4.62.0" 8 | } 9 | kubernetes = { 10 | source = "hashicorp/kubernetes" 11 | version = "2.19.0" 12 | } 13 | helm = { 14 | source = "hashicorp/helm" 15 | version = "2.6.0" 16 | } 17 | http = { 18 | source = "hashicorp/http" 19 | version = "3.2.1" 20 | } 21 | kubectl = { 22 | source = "gavinbunney/kubectl" 23 | version = "1.14.0" 24 | } 25 | } 26 | } 27 | 28 | data "aws_caller_identity" "current" {} 29 | -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/backup.tf: -------------------------------------------------------------------------------- 1 | resource "aws_backup_vault" "this" { 2 | name = var.name 3 | } 4 | 5 | resource "aws_backup_plan" "this" { 6 | name = var.name 7 | rule { 8 | rule_name = var.name 9 | target_vault_name = aws_backup_vault.this.name 10 | schedule = "cron(0 1 * * ? *)" 11 | lifecycle { 12 | delete_after = 30 13 | } 14 | } 15 | } 16 | 17 | resource "aws_backup_selection" "efs" { 18 | iam_role_arn = module.backup_role.iam_role_arn 19 | name = "${var.name}-efs" 20 | plan_id = aws_backup_plan.this.id 21 | 22 | resources = [ 23 | aws_efs_file_system.this.arn 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /terraform/modules/self-signed-certificate/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | default = "example" 4 | description = "" 5 | } 6 | 7 | variable "common_name" { 8 | type = string 9 | default = "localhost" 10 | description = "" 11 | } 12 | 13 | variable "dns_names" { 14 | type = list(any) 15 | default = ["localhost"] 16 | description = "" 17 | } 18 | 19 | variable "validity_period_hours" { 20 | type = string 21 | default = 8760 22 | description = "" 23 | } 24 | 25 | variable "early_renewal_hours" { 26 | type = string 27 | default = 336 28 | description = "" 29 | } 30 | -------------------------------------------------------------------------------- /docker/postgresql-backups/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/postgres:12-alpine 2 | 3 | #Install python and pip 4 | RUN echo "**** install Python ****" && \ 5 | apk add --no-cache python3 && \ 6 | if [ ! -e /usr/bin/python ]; then ln -sf python3 /usr/bin/python ; fi && \ 7 | \ 8 | echo "**** install pip ****" && \ 9 | python3 -m ensurepip && \ 10 | pip3 install --no-cache --upgrade pip setuptools wheel && \ 11 | if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi 12 | 13 | COPY requirements.txt . 14 | 15 | RUN pip install --upgrade --no-cache-dir -r requirements.txt 16 | 17 | COPY backup.py . 18 | 19 | ENTRYPOINT ["./backup.py"] 20 | 21 | -------------------------------------------------------------------------------- /helm-charts/elk/requirements.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: elasticsearch 3 | repository: https://helm.elastic.co 4 | version: 7.16.2 5 | - name: filebeat 6 | repository: https://helm.elastic.co 7 | version: 7.16.2 8 | - name: kibana 9 | repository: https://helm.elastic.co 10 | version: 7.16.2 11 | - name: logstash 12 | repository: https://helm.elastic.co 13 | version: 7.16.2 14 | - name: metricbeat 15 | repository: https://helm.elastic.co 16 | version: 7.16.2 17 | - name: apm-server 18 | repository: https://helm.elastic.co 19 | version: 7.16.2 20 | digest: sha256:c224fbba0c5c3212fb2d9165d962ef4f991e1eeb2146037f550fcb9f35988ea8 21 | generated: "2021-12-23T14:11:17.881693+06:00" 22 | -------------------------------------------------------------------------------- /helm-charts/elk/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/elastic/helm-charts/blob/7.8/elasticsearch/values.yaml 2 | elasticsearch: 3 | enabled: false 4 | 5 | # https://github.com/elastic/helm-charts/blob/7.8/kibana/values.yaml 6 | kibana: 7 | enabled: false 8 | 9 | # https://github.com/elastic/helm-charts/blob/7.8/filebeat/values.yaml 10 | filebeat: 11 | enabled: false 12 | 13 | # https://github.com/elastic/helm-charts/blob/7.8/metricbeat/values.yaml 14 | metricbeat: 15 | enabled: false 16 | 17 | # https://github.com/elastic/helm-charts/blob/7.8/logstash/values.yaml 18 | logstash: 19 | enabled: false 20 | 21 | # https://github.com/elastic/helm-charts/blob/7.8/apm-server/values.yaml 22 | apm-server: 23 | enabled: false 24 | -------------------------------------------------------------------------------- /helm-charts/elk/requirements.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: elasticsearch 3 | repository: https://helm.elastic.co 4 | version: 7.16.2 5 | condition: elasticsearch.enabled 6 | - name: filebeat 7 | repository: https://helm.elastic.co 8 | version: 7.16.2 9 | condition: filebeat.enabled 10 | - name: kibana 11 | repository: https://helm.elastic.co 12 | version: 7.16.2 13 | condition: kibana.enabled 14 | - name: logstash 15 | repository: https://helm.elastic.co 16 | version: 7.16.2 17 | condition: logstash.enabled 18 | - name: metricbeat 19 | repository: https://helm.elastic.co 20 | version: 7.16.2 21 | condition: metricbeat.enabled 22 | - name: apm-server 23 | repository: https://helm.elastic.co 24 | version: 7.16.2 25 | condition: apm-server.enabled 26 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # PR Description 2 | 3 | Please explain the changes you made here and link to any relevant issues. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] Documentation update 15 | 16 | # Checklist 17 | 18 | - [ ] My code follows the style guidelines of this project 19 | - [ ] I have performed a self-review of my own code 20 | - [ ] I have commented my code, particularly in hard-to-understand areas 21 | - [ ] I have made corresponding changes to the documentation 22 | -------------------------------------------------------------------------------- /terraform/modules/self-signed-certificate/main.tf: -------------------------------------------------------------------------------- 1 | resource "tls_private_key" "this" { 2 | algorithm = "RSA" 3 | } 4 | 5 | resource "tls_self_signed_cert" "this" { 6 | private_key_pem = tls_private_key.this.private_key_pem 7 | validity_period_hours = var.validity_period_hours 8 | early_renewal_hours = var.early_renewal_hours 9 | allowed_uses = [ 10 | "key_encipherment", 11 | "digital_signature", 12 | "server_auth", 13 | ] 14 | dns_names = var.dns_names 15 | subject { 16 | common_name = var.common_name 17 | organization = var.name 18 | } 19 | } 20 | 21 | data "external" "this_p8" { 22 | program = ["bash", "${path.module}/data-sources/p8.sh"] 23 | 24 | query = { 25 | private_key_pem = "${tls_private_key.this.private_key_pem}" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-eks-trusted/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "this" { 2 | name_prefix = var.name 3 | assume_role_policy = < [aws](#provider\_aws) | n/a | 10 | 11 | ## Modules 12 | 13 | No modules. 14 | 15 | ## Resources 16 | 17 | | Name | Type | 18 | |------|------| 19 | | [aws_ce_cost_allocation_tag.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ce_cost_allocation_tag) | resource | 20 | 21 | ## Inputs 22 | 23 | | Name | Description | Type | Default | Required | 24 | |------|-------------|------|---------|:--------:| 25 | | [tags](#input\_tags) | A list of tags to use for cost allocation tags |
list(object({
tag_key = string
status = string
}))
| n/a | yes | 26 | 27 | ## Outputs 28 | 29 | No outputs. 30 | -------------------------------------------------------------------------------- /terragrunt/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | terragrunt_version_constraint = ">= 0.39" 2 | skip = true 3 | 4 | locals { 5 | remote_state_bucket_region = "${get_env("TF_REMOTE_STATE_BUCKET_REGION")}" 6 | remote_state_bucket = "${get_env("TF_REMOTE_STATE_BUCKET")}" 7 | } 8 | 9 | remote_state { 10 | backend = "s3" 11 | generate = { 12 | path = "backend.tf" 13 | if_exists = "overwrite_terragrunt" 14 | } 15 | config = { 16 | region = local.remote_state_bucket_region 17 | bucket = local.remote_state_bucket 18 | key = "${path_relative_to_include()}/terraform.tfstate" 19 | encrypt = true 20 | # Uncomment this to use state locking 21 | # dynamodb_table = "${local.remote_state_bucket}-${path_relative_to_include()}" 22 | 23 | skip_metadata_api_check = true 24 | skip_credentials_validation = true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | Please answer the following questions for yourself before submitting an issue. **YOU MAY DELETE THE PREREQUISITES SECTION.** 4 | 5 | - [ ] I am running the latest version 6 | - [ ] I checked the documentation and found no answer 7 | - [ ] I checked to make sure that this issue has not already been filed 8 | 9 | # Expected Behavior 10 | 11 | Please describe the behavior you are expecting 12 | 13 | # Current Behavior 14 | 15 | What is the current behavior? 16 | 17 | # Failure Information (for bugs) 18 | 19 | Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. 20 | 21 | ## Steps to Reproduce 22 | 23 | Please provide detailed steps for reproducing the issue. 24 | 25 | 1. step 1 26 | 2. step 2 27 | 3. you get it... 28 | 29 | ## Context 30 | 31 | * Affected module version: 32 | * OS: 33 | * Terraform version: 34 | 35 | ## Any other relevant info including logs 36 | -------------------------------------------------------------------------------- /terraform/modules/eks-kubernetes-namespace/resourcequota.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "kubernetes_resource_quota" "this" { 3 | count = var.enable && length(var.resource_quotas) > 0 ? length(var.resource_quotas) : 0 4 | 5 | metadata { 6 | name = var.resource_quotas[count.index].name 7 | namespace = kubernetes_namespace.this[0].id 8 | } 9 | spec { 10 | hard = var.resource_quotas[count.index].hard 11 | scopes = lookup(var.resource_quotas[count.index], "scopes", null) 12 | dynamic "scope_selector" { 13 | for_each = lookup(var.resource_quotas[count.index], "scope_selector", null) != null ? [var.resource_quotas[count.index].scope_selector] : [] 14 | content { 15 | match_expression { 16 | scope_name = lookup(scope_selector.value, "scope_name", null) 17 | operator = lookup(scope_selector.value, "operator", null) 18 | values = lookup(scope_selector.value, "values", null) 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | # Always validate the PR title, and ignore the commits 2 | titleOnly: true 3 | 4 | # Always validate all commits, and ignore the PR title 5 | commitsOnly: false 6 | 7 | # Always validate the PR title AND all the commits 8 | titleAndCommits: false 9 | 10 | # Require at least one commit to be valid 11 | # this is only relevant when using commitsOnly: true or titleAndCommits: true, 12 | # which validate all commits by default 13 | anyCommit: false 14 | 15 | # By default types specified in commitizen/conventional-commit-types is used. 16 | # See: https://github.com/commitizen/conventional-commit-types/blob/v2.3.0/index.json 17 | # You can override the valid types 18 | types: 19 | - feat 20 | - fix 21 | - improvement 22 | - enh 23 | - doc 24 | - refactor 25 | - test 26 | - ci 27 | - chore 28 | 29 | # Allow use of Merge commits (eg on github: "Merge branch 'master' into feature/ride-unicorns") 30 | # this is only relevant when using commitsOnly: true (or titleAndCommits: true) 31 | allowMergeCommits: false 32 | -------------------------------------------------------------------------------- /terraform/layer1-aws/aws-pritunl.tf: -------------------------------------------------------------------------------- 1 | #tfsec:ignore:aws-vpc-no-public-egress-sgr tfsec:ignore:aws-vpc-no-public-ingress-sgr 2 | module "pritunl" { 3 | count = var.pritunl_vpn_server_enable ? 1 : 0 4 | 5 | source = "../modules/aws-pritunl" 6 | environment = local.env 7 | vpc_id = module.vpc.vpc_id 8 | public_subnets = module.vpc.public_subnets 9 | private_subnets = module.vpc.private_subnets 10 | ingress_with_cidr_blocks = [ 11 | { 12 | protocol = "6" 13 | from_port = 443 14 | to_port = 443 15 | cidr_blocks = var.pritunl_vpn_access_cidr_blocks 16 | }, 17 | { 18 | protocol = "17" 19 | from_port = 19739 # this is a port that we will set in pritunl server configuration (after installation) 20 | to_port = 19739 21 | cidr_blocks = "0.0.0.0/0" 22 | }, 23 | { 24 | protocol = "6" 25 | from_port = 80 26 | to_port = 80 27 | cidr_blocks = var.pritunl_vpn_access_cidr_blocks 28 | }, 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/security_groups.tf: -------------------------------------------------------------------------------- 1 | module "ec2_sg" { 2 | source = "terraform-aws-modules/security-group/aws" 3 | version = "4.8.0" 4 | 5 | name = var.name 6 | description = "${var.name} security group" 7 | vpc_id = var.vpc_id 8 | 9 | ingress_with_source_security_group_id = var.ingress_with_source_security_group_id 10 | 11 | ingress_with_cidr_blocks = var.ingress_with_cidr_blocks 12 | 13 | egress_with_cidr_blocks = [ 14 | { 15 | protocol = "-1" 16 | from_port = 0 17 | to_port = 0 18 | cidr_blocks = "0.0.0.0/0" 19 | } 20 | ] 21 | } 22 | 23 | module "efs_sg" { 24 | source = "terraform-aws-modules/security-group/aws" 25 | version = "4.8.0" 26 | 27 | name = "${var.name}-efs" 28 | description = "${var.name} efs security group" 29 | vpc_id = var.vpc_id 30 | 31 | ingress_with_source_security_group_id = [ 32 | { 33 | protocol = "6" 34 | from_port = 2049 35 | to_port = 2049 36 | source_security_group_id = module.ec2_sg.security_group_id 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /.chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/maddevsio/aws-eks-base 6 | options: 7 | commits: 8 | sort_by: Type 9 | filters: 10 | Type: 11 | - feat 12 | - fix 13 | - improvement 14 | - enh 15 | - doc 16 | - refactor 17 | - test 18 | - ci 19 | 20 | commit_groups: 21 | group_by: Type 22 | sort_by: Custom 23 | title_order: 24 | - feat 25 | - improvement 26 | - enh 27 | - refactor 28 | - fix 29 | - doc 30 | - test 31 | - ci 32 | title_maps: 33 | feat: FEATURES 34 | fix: BUG FIXES 35 | improvement: ENHANCEMENTS 36 | enh: ENHANCEMENTS 37 | doc: DOCS 38 | refactor: REFACTORS 39 | test: TESTS 40 | ci: CI 41 | 42 | header: 43 | pattern: "^(.+)\\s*:\\s*(.+)$" 44 | pattern_maps: 45 | - Type 46 | - Subject 47 | 48 | notes: 49 | keywords: 50 | - BREAKING CHANGES 51 | - NOTES 52 | 53 | refs: 54 | actions: 55 | - Closes 56 | - Fixes 57 | - Resolves 58 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/providers.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | allowed_account_ids = var.allowed_account_ids 4 | } 5 | 6 | provider "kubernetes" { 7 | host = data.aws_eks_cluster.main.endpoint 8 | cluster_ca_certificate = base64decode(data.aws_eks_cluster.main.certificate_authority.0.data) 9 | token = data.aws_eks_cluster_auth.main.token 10 | } 11 | 12 | provider "kubectl" { 13 | host = data.aws_eks_cluster.main.endpoint 14 | cluster_ca_certificate = base64decode(data.aws_eks_cluster.main.certificate_authority.0.data) 15 | token = data.aws_eks_cluster_auth.main.token 16 | } 17 | 18 | provider "helm" { 19 | kubernetes { 20 | host = data.aws_eks_cluster.main.endpoint 21 | cluster_ca_certificate = base64decode(data.aws_eks_cluster.main.certificate_authority.0.data) 22 | token = data.aws_eks_cluster_auth.main.token 23 | } 24 | 25 | experiments { 26 | manifest = true 27 | } 28 | } 29 | 30 | data "aws_eks_cluster" "main" { 31 | name = local.eks_cluster_id 32 | } 33 | 34 | data "aws_eks_cluster_auth" "main" { 35 | name = local.eks_cluster_id 36 | } 37 | -------------------------------------------------------------------------------- /helm-charts/pg-exporter-user/templates/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: {{ include "pg-exporter-user.fullname" . }} 5 | labels: 6 | {{- include "pg-exporter-user.labels" . | nindent 4 }} 7 | spec: 8 | activeDeadlineSeconds: {{ .Values.activeDeadlineSeconds }} 9 | backoffLimit: {{ .Values.backoffLimit }} 10 | ttlSecondsAfterFinished: {{ .Values.ttlSecondsAfterFinished }} 11 | template: 12 | metadata: 13 | labels: 14 | {{- include "pg-exporter-user.selectorLabels" . | nindent 8 }} 15 | spec: 16 | restartPolicy: OnFailure 17 | containers: 18 | - name: {{ .Chart.Name }} 19 | image: {{ .Values.image.repository }}:{{ .Values.image.tag }} 20 | env: 21 | {{- if .Values.Envs }} 22 | {{ toYaml .Values.Envs | nindent 12 }} 23 | {{- end }} 24 | {{- with .Values.args }} 25 | args: 26 | {{- toYaml . | nindent 12 }} 27 | {{- end }} 28 | {{- with .Values.command }} 29 | command: 30 | {{- toYaml . | nindent 12 }} 31 | {{- end }} 32 | resources: 33 | {{- toYaml .Values.resources | nindent 12 }} 34 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | region = var.region 3 | short_region = var.short_region[var.region] 4 | name = "${var.name}-${local.env}-${local.short_region}" 5 | name_wo_region = "${var.name}-${local.env}" 6 | env = var.environment 7 | zone_id = var.zone_id 8 | domain_name = var.domain_name 9 | domain_suffix = "${local.env}.${var.domain_name}" 10 | allowed_ips = var.allowed_ips 11 | ip_whitelist = join(",", concat(local.allowed_ips, var.additional_allowed_ips)) 12 | vpc_id = var.vpc_id 13 | vpc_cidr = var.vpc_cidr 14 | eks_cluster_id = var.eks_cluster_id 15 | eks_certificate_authority_data = data.aws_eks_cluster.main.certificate_authority.0.data 16 | eks_cluster_endpoint = data.aws_eks_cluster.main.endpoint 17 | eks_cluster_arn = data.aws_eks_cluster.main.arn 18 | eks_oidc_provider_arn = var.eks_oidc_provider_arn 19 | ssl_certificate_arn = var.ssl_certificate_arn 20 | 21 | helm_releases = yamldecode(file("${path.module}/helm-releases.yaml"))["releases"] 22 | } 23 | -------------------------------------------------------------------------------- /terraform/modules/eks-kubernetes-namespace/variables.tf: -------------------------------------------------------------------------------- 1 | variable "annotations" { 2 | type = map(any) 3 | default = {} 4 | description = "An unstructured key value map stored with the namespace that may be used to store arbitrary metadata" 5 | } 6 | 7 | variable "labels" { 8 | type = map(any) 9 | default = {} 10 | description = "Map of string keys and values that can be used to organize and categorize (scope and select) namespaces." 11 | } 12 | 13 | variable "name" { 14 | type = string 15 | description = "Name of the namespace, must be unique. Cannot be updated." 16 | } 17 | 18 | variable "depends" { 19 | type = any 20 | default = null 21 | description = "Indicates the resource this resource depends on." 22 | } 23 | 24 | variable "enable" { 25 | type = bool 26 | default = true 27 | description = "If set to true, create namespace" 28 | } 29 | 30 | variable "limits" { 31 | type = any 32 | default = [ 33 | { 34 | type = "Container" 35 | default = { 36 | memory = "128Mi" 37 | } 38 | default_request = { 39 | cpu = "100m" 40 | memory = "64Mi" 41 | } 42 | } 43 | ] 44 | } 45 | 46 | variable "resource_quotas" { 47 | type = any 48 | default = [] 49 | } 50 | 51 | variable "network_policies" { 52 | type = any 53 | default = [] 54 | } 55 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-eks-trusted/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [aws](#provider\_aws) | n/a | 11 | 12 | ## Modules 13 | 14 | No modules. 15 | 16 | ## Resources 17 | 18 | | Name | Type | 19 | |------|------| 20 | | [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 21 | | [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | 22 | 23 | ## Inputs 24 | 25 | | Name | Description | Type | Default | Required | 26 | |------|-------------|------|---------|:--------:| 27 | | [name](#input\_name) | Name, required to form unique resource names | `any` | n/a | yes | 28 | | [oidc\_provider\_arn](#input\_oidc\_provider\_arn) | The ARN of the OIDC Provider | `any` | n/a | yes | 29 | | [policy](#input\_policy) | The policy that will be attached to role | `any` | n/a | yes | 30 | | [region](#input\_region) | Target region for all infrastructure resources | `any` | n/a | yes | 31 | 32 | ## Outputs 33 | 34 | | Name | Description | 35 | |------|-------------| 36 | | [role\_arn](#output\_role\_arn) | This role ARN | 37 | -------------------------------------------------------------------------------- /terraform/modules/aws-iam-user-with-policy/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [aws](#provider\_aws) | n/a | 11 | 12 | ## Modules 13 | 14 | No modules. 15 | 16 | ## Resources 17 | 18 | | Name | Type | 19 | |------|------| 20 | | [aws_iam_access_key.this_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource | 21 | | [aws_iam_user.this_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource | 22 | | [aws_iam_user_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy) | resource | 23 | 24 | ## Inputs 25 | 26 | | Name | Description | Type | Default | Required | 27 | |------|-------------|------|---------|:--------:| 28 | | [name](#input\_name) | Project name, required to form unique resource names | `any` | n/a | yes | 29 | | [policy](#input\_policy) | IAM policy that will be attached to user | `any` | n/a | yes | 30 | 31 | ## Outputs 32 | 33 | | Name | Description | 34 | |------|-------------| 35 | | [access\_key\_id](#output\_access\_key\_id) | AWS ACCESS\_KEY\_ID | 36 | | [access\_secret\_key](#output\_access\_secret\_key) | AWS ACCESS\_SECRET\_KEY | 37 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: 2 | name: hashicorp/terraform:0.14.6 3 | entrypoint: 4 | - '/usr/bin/env' 5 | - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' 6 | 7 | cache: 8 | key: terraform_dir 9 | paths: 10 | - $CI_PROJECT_DIR/terraform/layer1-aws/.terraform 11 | - $CI_PROJECT_DIR/terraform/layer2-k8s/.terraform 12 | - $CI_PROJECT_DIR/terraform/layer1-aws/.terraform.lock.hcl 13 | - $CI_PROJECT_DIR/terraform/layer2-k8s/.terraform.lock.hcl 14 | 15 | stages: 16 | - init 17 | - check 18 | 19 | terraform_init: 20 | stage: init 21 | script: 22 | - cd $CI_PROJECT_DIR/terraform/layer1-aws 23 | - terraform init -backend=false 24 | - cd $CI_PROJECT_DIR/terraform/layer2-k8s 25 | - terraform init -backend=false 26 | 27 | terraform_format: 28 | stage: check 29 | script: 30 | - terraform fmt -recursive -write=false -check . 31 | 32 | terraform_validate: 33 | stage: check 34 | script: 35 | - cd $CI_PROJECT_DIR/terraform/layer1-aws 36 | - terraform validate -no-color . 37 | - cd $CI_PROJECT_DIR/terraform/layer2-k8s 38 | - terraform validate -no-color . 39 | 40 | terraform_tflint: 41 | image: 42 | name: wata727/tflint 43 | entrypoint: 44 | - '/usr/bin/env' 45 | - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' 46 | stage: check 47 | script: 48 | - cd $CI_PROJECT_DIR/terraform/layer1-aws 49 | - tflint --no-color 50 | - cd $CI_PROJECT_DIR/terraform/layer2-k8s 51 | - tflint --no-color 52 | -------------------------------------------------------------------------------- /helm-charts/postgresql-backups/templates/scheduler.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.scheduler.enabled }} 2 | apiVersion: batch/v1beta1 3 | kind: CronJob 4 | metadata: 5 | name: {{ include "scheduler.jobname" . }} 6 | labels: 7 | {{- include "postgresql-backups.labels" . | nindent 4 }} 8 | annotations: 9 | secret.reloader.stakater.com/reload: {{ include "scheduler.jobname" . }} 10 | spec: 11 | jobTemplate: 12 | spec: 13 | template: 14 | metadata: 15 | labels: 16 | {{- include "postgresql-backups.selectorLabels" . | nindent 12 }} 17 | spec: 18 | containers: 19 | - name: {{ include "scheduler.jobname" . }} 20 | image: {{ .Values.image.repository }}:{{ .Values.image.tag }} 21 | imagePullPolicy: {{ .Values.image.pullPolicy }} 22 | envFrom: 23 | - secretRef: 24 | name: {{ include "postgresql-backups.fullname" . }} 25 | command: {{ .Values.scheduler.command }} 26 | {{- with .Values.scheduler.args }} 27 | args: 28 | {{ toYaml . | nindent 14 }} 29 | {{- end }} 30 | resources: 31 | {{- toYaml .Values.scheduler.resources | nindent 14 }} 32 | restartPolicy: {{ .Values.scheduler.restartPolicy }} 33 | schedule: {{ .Values.scheduler.schedule | quote }} 34 | successfulJobsHistoryLimit: {{ .Values.scheduler.successfulJobsHistoryLimit }} 35 | concurrencyPolicy: {{ .Values.scheduler.concurrencyPolicy }} 36 | failedJobsHistoryLimit: {{ .Values.scheduler.failedJobsHistoryLimit }} 37 | {{- end }} 38 | -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vpc_id" { 2 | type = string 3 | description = "ID of the VPC where to create security groups" 4 | } 5 | 6 | variable "public_subnets" { 7 | type = list(any) 8 | description = "A list of public subnets where Pritunl server will be run" 9 | } 10 | 11 | variable "private_subnets" { 12 | type = list(any) 13 | description = "A list of private subnets where EFS will be created" 14 | } 15 | 16 | variable "name" { 17 | default = "pritunl" 18 | description = "Name used for all resources in this module" 19 | } 20 | 21 | variable "environment" { 22 | default = "infra" 23 | description = "Environment name" 24 | } 25 | 26 | variable "instance_type" { 27 | default = "t3.small" 28 | description = "Pritunl server instance type" 29 | } 30 | 31 | variable "encrypted" { 32 | default = true 33 | description = "Encrypt or not EFS" 34 | } 35 | 36 | variable "kms_key_id" { 37 | default = null 38 | description = "KMS key ID in case of using CMK" 39 | } 40 | 41 | variable "ingress_with_source_security_group_id" { 42 | type = list(object({ 43 | protocol = string 44 | from_port = string 45 | to_port = string 46 | security_groups = string 47 | })) 48 | 49 | default = [] 50 | description = "A list of Pritunl server security group rules where source is another security group" 51 | } 52 | 53 | variable "ingress_with_cidr_blocks" { 54 | type = list(object({ 55 | protocol = string 56 | from_port = string 57 | to_port = string 58 | cidr_blocks = string 59 | })) 60 | 61 | default = [] 62 | description = "A list of Pritunl server security group rules where source is CIDR" 63 | } 64 | -------------------------------------------------------------------------------- /examples/echoserver-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: echoserver 6 | namespace: fargate 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: echoserver 12 | template: 13 | metadata: 14 | labels: 15 | app: echoserver 16 | spec: 17 | containers: 18 | - image: gcr.io/google_containers/echoserver:1.0 19 | imagePullPolicy: Always 20 | name: echoserver 21 | ports: 22 | - containerPort: 8080 23 | --- 24 | apiVersion: v1 25 | kind: Service 26 | metadata: 27 | name: echoserver 28 | namespace: fargate 29 | spec: 30 | ports: 31 | - port: 80 32 | targetPort: 8080 33 | protocol: TCP 34 | selector: 35 | app: echoserver 36 | type: NodePort 37 | --- 38 | apiVersion: extensions/v1beta1 39 | kind: Ingress 40 | metadata: 41 | name: echoserver 42 | namespace: fargate 43 | annotations: 44 | kubernetes.io/ingress.class: alb 45 | alb.ingress.kubernetes.io/scheme: internet-facing 46 | alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01 47 | alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:730809894724:certificate/fa029132-86ab-4342-96e2-8e1fd5c56c29 48 | alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' 49 | alb.ingress.kubernetes.io/target-type: ip 50 | external-dns.alpha.kubernetes.io/hostname: echo.maddevs.org 51 | alb.ingress.kubernetes.io/success-codes: "200" 52 | alb.ingress.kubernetes.io/healthcheck-path: "/" 53 | spec: 54 | rules: 55 | - host: echo.maddevs.org 56 | http: 57 | paths: 58 | - path: / 59 | backend: 60 | serviceName: echoserver 61 | servicePort: 80 62 | -------------------------------------------------------------------------------- /terraform/layer1-aws/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.4.4" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "5.1.0" 8 | } 9 | kubernetes = { 10 | source = "hashicorp/kubernetes" 11 | version = "2.19.0" 12 | } 13 | } 14 | } 15 | 16 | data "aws_availability_zones" "available" {} 17 | 18 | data "aws_caller_identity" "current" {} 19 | 20 | resource "aws_ebs_encryption_by_default" "default" { 21 | enabled = true 22 | } 23 | 24 | resource "aws_iam_account_password_policy" "default" { 25 | count = var.aws_account_password_policy.create ? 1 : 0 26 | 27 | minimum_password_length = var.aws_account_password_policy.minimum_password_length 28 | password_reuse_prevention = var.aws_account_password_policy.password_reuse_prevention 29 | require_lowercase_characters = var.aws_account_password_policy.require_lowercase_characters 30 | require_numbers = var.aws_account_password_policy.require_numbers 31 | require_uppercase_characters = var.aws_account_password_policy.require_uppercase_characters 32 | require_symbols = var.aws_account_password_policy.require_symbols 33 | allow_users_to_change_password = var.aws_account_password_policy.allow_users_to_change_password 34 | max_password_age = var.aws_account_password_policy.max_password_age 35 | } 36 | 37 | 38 | module "aws_cost_allocation_tags" { 39 | count = var.is_this_payment_account ? 1 : 0 40 | 41 | source = "../modules/aws-cost-allocation-tags" 42 | tags = [ 43 | { 44 | tag_key = "Environment" 45 | status = "Active" 46 | }, 47 | { 48 | tag_key = "Terraform" 49 | status = "Active" 50 | }, 51 | { 52 | tag_key = "aws:autoscaling:groupName" 53 | status = "Active" 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /docker/postgresql-backups/README.md: -------------------------------------------------------------------------------- 1 | # Base image for postgresql-backups 2 | 3 | * This docker image contains a python script for creating a backup of a postgresql database. 4 | * After creating the database dump, the dump is copied to the s3 bucket. 5 | * If it succeeds or if there is an error when creating the dump or copying, there is a notification in the slack. 6 | 7 | # Build and push docker image 8 | 9 | * Build docker image 10 | 11 | ```yaml 12 | docker build -t postgresql-backups . 13 | ``` 14 | 15 | ```yaml 16 | docker tag postgresql-backups ecr-repository-url 17 | ``` 18 | 19 | ```yaml 20 | docker push ecr-repository-url 21 | ``` 22 | 23 | # Auth in AWS 24 | 25 | * Use `AWS CLI` for default authentication 26 | 27 | or 28 | 29 | * Path AWS authentication variables to docker container 30 | 31 | # Run docker container locally 32 | 33 | ```docker 34 | docker run -d --name postgresql-backups -e AWS_ACCESS_KEY_ID=aws-access-key-id -e AWS_SECRET_ACCESS_KEY=aws-access-secret-key -e AWS_BUCKET_REGION=eu-west-1 -e AWS_BUCKET_NAME=aws-bucket-name -e SLACK_URL=slack-web-hook -e PG_HOST=postgres -e PG_PORT=5432 -e PG_USER=postgres -e PG_DATABASE=pg_db -e PG_PASS=postgres postgresql-backups 35 | ``` 36 | 37 | # Show logs 38 | 39 | ```docker 40 | docker logs postgresql-backups 41 | ``` 42 | 43 | * Environment variables 44 | 45 | ```yaml 46 | # Optional variable 47 | SLACK_URL=slack-notification-url 48 | 49 | # Requered variables 50 | AWS_ACCESS_KEY_ID=aws-access-key-id 51 | AWS_SECRET_ACCESS_KEY=aws-access-secret-key 52 | AWS_BUCKET_REGION=aws-bucket-region 53 | AWS_BUCKET_NAME=bucket-name-for-backups 54 | PG_HOST=postgresql-host 55 | PG_PORT=5432 56 | PG_USER=postgres 57 | PG_DATABASE=pg_db 58 | PG_PASS=postgres 59 | ``` 60 | 61 | >Note 62 | Setting this variables `SLACK_URL` is optional. 63 | If the variable is not set, no notifications are sent to the slack. 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /terraform/modules/self-signed-certificate/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [external](#provider\_external) | n/a | 11 | | [tls](#provider\_tls) | n/a | 12 | 13 | ## Modules 14 | 15 | No modules. 16 | 17 | ## Resources 18 | 19 | | Name | Type | 20 | |------|------| 21 | | [tls_private_key.this](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource | 22 | | [tls_self_signed_cert.this](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/self_signed_cert) | resource | 23 | | [external_external.this_p8](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source | 24 | 25 | ## Inputs 26 | 27 | | Name | Description | Type | Default | Required | 28 | |------|-------------|------|---------|:--------:| 29 | | [common\_name](#input\_common\_name) | n/a | `string` | `"localhost"` | no | 30 | | [dns\_names](#input\_dns\_names) | n/a | `list(any)` |
[
"localhost"
]
| no | 31 | | [early\_renewal\_hours](#input\_early\_renewal\_hours) | n/a | `string` | `336` | no | 32 | | [name](#input\_name) | n/a | `string` | `"example"` | no | 33 | | [validity\_period\_hours](#input\_validity\_period\_hours) | n/a | `string` | `8760` | no | 34 | 35 | ## Outputs 36 | 37 | | Name | Description | 38 | |------|-------------| 39 | | [cert\_pem](#output\_cert\_pem) | n/a | 40 | | [p8](#output\_p8) | n/a | 41 | | [private\_key\_pem](#output\_private\_key\_pem) | n/a | 42 | 43 | -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/templates/user-data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | 4 | 5 | yum install -y amazon-efs-utils 6 | 7 | export AWS_DEFAULT_REGION="${aws_region}" 8 | MONGODB_DATA_DIR="/var/lib/mongo" 9 | 10 | echo "* hard nofile 64000" >> /etc/security/limits.conf 11 | echo "* soft nofile 64000" >> /etc/security/limits.conf 12 | echo "root hard nofile 64000" >> /etc/security/limits.conf 13 | echo "root soft nofile 64000" >> /etc/security/limits.conf 14 | 15 | INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id) 16 | 17 | 18 | # Attach EIP 19 | aws ec2 associate-address --instance-id $${INSTANCE_ID} --allocation-id ${eipalloc} --allow-reassociation 20 | 21 | # Change source-destination checking 22 | aws ec2 modify-instance-attribute --instance-id $${INSTANCE_ID} --source-dest-check "{\"Value\": false}" 23 | 24 | tee /etc/yum.repos.d/mongodb-org-4.2.repo << EOF 25 | [mongodb-org-4.2] 26 | name=MongoDB Repository 27 | baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.2/x86_64/ 28 | gpgcheck=1 29 | enabled=1 30 | gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc 31 | EOF 32 | 33 | tee /etc/yum.repos.d/pritunl.repo << EOF 34 | [pritunl] 35 | name=Pritunl Repository 36 | baseurl=https://repo.pritunl.com/stable/yum/amazonlinux/2/ 37 | gpgcheck=1 38 | enabled=1 39 | EOF 40 | 41 | rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 42 | gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 7568D9BB55FF9E5287D586017AE645C0CF8E292A 43 | gpg --armor --export 7568D9BB55FF9E5287D586017AE645C0CF8E292A > key.tmp; rpm --import key.tmp; rm -f key.tmp 44 | yum -y install pritunl mongodb-org 45 | 46 | # Mount EFS filesystem 47 | mount -t efs -o tls ${efs_id}:/ $${MONGODB_DATA_DIR} 48 | chown -R mongod:mongod $${MONGODB_DATA_DIR} 49 | echo "${efs_id}:/ $${MONGODB_DATA_DIR} efs _netdev,tls 0 0" >> /etc/fstab 50 | 51 | systemctl enable mongod pritunl 52 | pritunl set-mongodb 'mongodb://localhost:27017/pritunl' 53 | 54 | 55 | systemctl start mongod pritunl 56 | -------------------------------------------------------------------------------- /helm-charts/elk/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "elk.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 7 | {{- end }} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "elk.fullname" -}} 15 | {{- if .Values.fullnameOverride }} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 17 | {{- else }} 18 | {{- $name := default .Chart.Name .Values.nameOverride }} 19 | {{- if contains $name .Release.Name }} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 21 | {{- else }} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 23 | {{- end }} 24 | {{- end }} 25 | {{- end }} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "elk.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 32 | {{- end }} 33 | 34 | {{/* 35 | Common labels 36 | */}} 37 | {{- define "elk.labels" -}} 38 | helm.sh/chart: {{ include "elk.chart" . }} 39 | {{ include "elk.selectorLabels" . }} 40 | {{- if .Chart.AppVersion }} 41 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 42 | {{- end }} 43 | app.kubernetes.io/managed-by: {{ .Release.Service }} 44 | {{- end }} 45 | 46 | {{/* 47 | Selector labels 48 | */}} 49 | {{- define "elk.selectorLabels" -}} 50 | app.kubernetes.io/name: {{ include "elk.name" . }} 51 | app.kubernetes.io/instance: {{ .Release.Name }} 52 | {{- end }} 53 | 54 | {{/* 55 | Create the name of the service account to use 56 | */}} 57 | {{- define "elk.serviceAccountName" -}} 58 | {{- if .Values.serviceAccount.create }} 59 | {{- default (include "elk.fullname" .) .Values.serviceAccount.name }} 60 | {{- else }} 61 | {{- default "default" .Values.serviceAccount.name }} 62 | {{- end }} 63 | {{- end }} 64 | -------------------------------------------------------------------------------- /docker/aws-eks-utils/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/alpine:3.15.4 2 | 3 | ARG TERRAFORM_VERSION="1.1.8" 4 | ARG TERRAGRUNT_VERSION="0.39.1" 5 | ARG HELM_VERSION="3.8.2" 6 | ARG HELMFILE_VERSION="0.144.0" 7 | ARG KUBECTL_VERSION="1.22.0" 8 | ENV BASE_URL="https://get.helm.sh" 9 | ENV TAR_FILE="helm-v${HELM_VERSION}-linux-amd64.tar.gz" 10 | 11 | #Install python and pip 12 | RUN echo "**** install Python ****" && \ 13 | apk add --no-cache python3 && \ 14 | if [ ! -e /usr/bin/python ]; then ln -sf python3 /usr/bin/python ; fi && \ 15 | \ 16 | echo "**** install pip ****" && \ 17 | python3 -m ensurepip && \ 18 | pip3 install --no-cache --upgrade pip setuptools wheel && \ 19 | if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi 20 | 21 | #Install additional packages and helm 22 | RUN apk add --update --no-cache openssl git jq bash curl wget unzip ca-certificates && \ 23 | curl -L ${BASE_URL}/${TAR_FILE} |tar xvz && \ 24 | mv linux-amd64/helm /usr/bin/helm && \ 25 | chmod +x /usr/bin/helm 26 | 27 | WORKDIR /tmp 28 | 29 | #Install tfenv for terraform 30 | RUN git clone https://github.com/tfutils/tfenv.git /usr/bin/.tfenv && \ 31 | ln -s /usr/bin/.tfenv/bin/* /usr/bin 32 | 33 | #Intall tgenv for terragrunt 34 | RUN git clone https://github.com/cunymatthieu/tgenv.git /usr/bin/.tgenv && \ 35 | ln -s /usr/bin/.tgenv/bin/* /usr/bin 36 | 37 | #Install terraform 38 | RUN tfenv install $TERRAFORM_VERSION 39 | 40 | #Install terragrunt 41 | RUN tgenv install $TERRAGRUNT_VERSION 42 | 43 | #Install aws-cli 44 | RUN pip install awscli --upgrade 45 | 46 | #Install kubectl 47 | RUN wget https://storage.googleapis.com/kubernetes-release/release/v"$KUBECTL_VERSION"/bin/linux/amd64/kubectl \ 48 | && chmod +x kubectl && mv kubectl /bin/kubectl 49 | 50 | #Install docker 51 | RUN apk add --no-cache --update docker 52 | 53 | #Install helmfile 54 | RUN wget https://github.com/roboll/helmfile/releases/download/v${HELMFILE_VERSION}/helmfile_linux_amd64 \ 55 | && chmod +x helmfile_linux_amd64 && mv helmfile_linux_amd64 /bin/helmfile 56 | 57 | # Install ssh 58 | RUN apk add openssh 59 | 60 | ENTRYPOINT [""] 61 | -------------------------------------------------------------------------------- /helm-charts/pg-exporter-user/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "pg-exporter-user.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "pg-exporter-user.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "pg-exporter-user.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "pg-exporter-user.labels" -}} 37 | helm.sh/chart: {{ include "pg-exporter-user.chart" . }} 38 | {{ include "pg-exporter-user.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "pg-exporter-user.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "pg-exporter-user.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "pg-exporter-user.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "pg-exporter-user.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /terraform/modules/aws-pritunl/main.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "current" {} 2 | resource "aws_eip" "this" { 3 | domain = "vpc" 4 | tags = { 5 | Name = var.name 6 | Environment = var.environment 7 | } 8 | } 9 | 10 | resource "aws_launch_template" "this" { 11 | name_prefix = var.name 12 | image_id = data.aws_ami.amazon_linux_2.id 13 | instance_type = var.instance_type 14 | ebs_optimized = false 15 | vpc_security_group_ids = [module.ec2_sg.security_group_id] 16 | 17 | iam_instance_profile { 18 | arn = aws_iam_instance_profile.this_instance_profile.arn 19 | } 20 | 21 | metadata_options { 22 | http_endpoint = "enabled" 23 | http_tokens = "optional" 24 | http_put_response_hop_limit = 3 25 | } 26 | 27 | user_data = base64encode(templatefile("${path.module}/templates/user-data.sh", 28 | { 29 | aws_region = data.aws_region.current.name 30 | eipalloc = aws_eip.this.id 31 | efs_id = aws_efs_file_system.this.id 32 | }) 33 | ) 34 | 35 | monitoring { 36 | enabled = false 37 | } 38 | 39 | tag_specifications { 40 | resource_type = "instance" 41 | 42 | tags = { 43 | Name = var.name 44 | } 45 | } 46 | 47 | depends_on = [aws_efs_mount_target.this] 48 | 49 | } 50 | 51 | resource "aws_autoscaling_group" "this" { 52 | name = var.name 53 | desired_capacity = 1 54 | max_size = 1 55 | min_size = 1 56 | default_cooldown = 30 57 | force_delete = true 58 | termination_policies = ["OldestLaunchTemplate", "OldestInstance"] 59 | 60 | launch_template { 61 | id = aws_launch_template.this.id 62 | version = "$Latest" 63 | } 64 | 65 | vpc_zone_identifier = var.public_subnets 66 | 67 | tag { 68 | key = "Name" 69 | value = var.name 70 | propagate_at_launch = true 71 | } 72 | 73 | tag { 74 | key = "Environment" 75 | value = var.environment 76 | propagate_at_launch = true 77 | } 78 | 79 | lifecycle { 80 | create_before_destroy = true 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/eks-reloader.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | reloader = { 3 | name = local.helm_releases[index(local.helm_releases.*.id, "reloader")].id 4 | enabled = local.helm_releases[index(local.helm_releases.*.id, "reloader")].enabled 5 | chart = local.helm_releases[index(local.helm_releases.*.id, "reloader")].chart 6 | repository = local.helm_releases[index(local.helm_releases.*.id, "reloader")].repository 7 | chart_version = local.helm_releases[index(local.helm_releases.*.id, "reloader")].chart_version 8 | namespace = local.helm_releases[index(local.helm_releases.*.id, "reloader")].namespace 9 | } 10 | } 11 | 12 | module "reloader_namespace" { 13 | count = local.reloader.enabled ? 1 : 0 14 | 15 | source = "../modules/eks-kubernetes-namespace" 16 | name = local.reloader.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.reloader.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 | } 58 | 59 | resource "helm_release" "reloader" { 60 | count = local.reloader.enabled ? 1 : 0 61 | 62 | name = local.reloader.name 63 | chart = local.reloader.chart 64 | repository = local.reloader.repository 65 | version = local.reloader.chart_version 66 | namespace = module.reloader_namespace[count.index].name 67 | max_history = var.helm_release_history_size 68 | } 69 | -------------------------------------------------------------------------------- /terragrunt/demo/us-east-1/k8s-addons/terragrunt.hcl: -------------------------------------------------------------------------------- 1 | include "root" { 2 | path = find_in_parent_folders() 3 | expose = true 4 | merge_strategy = "deep" 5 | } 6 | 7 | include "env" { 8 | path = find_in_parent_folders("env.hcl") 9 | expose = true 10 | merge_strategy = "deep" 11 | } 12 | 13 | terraform { 14 | source = "${get_terragrunt_dir()}/../../../../terraform//layer2-k8s" 15 | } 16 | 17 | dependencies { 18 | paths = ["../aws-base"] 19 | } 20 | 21 | dependency "aws-base" { 22 | config_path = "../aws-base" 23 | 24 | mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] 25 | 26 | mock_outputs = { 27 | route53_zone_id = "Z058363314IT7VAKRA777" 28 | vpc_id = "vpc-0f5b1b5f788888888" 29 | vpc_cidr = "10.0.0.0/16" 30 | eks_cluster_id = "maddevs-demo-use1" 31 | eks_oidc_provider_arn = "arn:aws:iam::730808884724:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/D55EEBDFE5510B81EEE2381B88888888" 32 | ssl_certificate_arn = "arn:aws:acm:us-east-1:730808884724:certificate/fa029132-86ab-7777-8888-8e1fd5c56c29" 33 | node_group_default_iam_role_arn = "arn:aws:iam::731118884724:role/maddevs-demo-use1-default-202312sdfdsfs52134060000000a" 34 | node_group_default_iam_role_name = "test" 35 | } 36 | } 37 | 38 | inputs = { 39 | zone_id = dependency.aws-base.outputs.route53_zone_id 40 | vpc_id = dependency.aws-base.outputs.vpc_id 41 | vpc_cidr = dependency.aws-base.outputs.vpc_cidr 42 | eks_cluster_id = dependency.aws-base.outputs.eks_cluster_id 43 | eks_oidc_provider_arn = dependency.aws-base.outputs.eks_oidc_provider_arn 44 | ssl_certificate_arn = dependency.aws-base.outputs.ssl_certificate_arn 45 | node_group_default_iam_role_arn = dependency.aws-base.outputs.node_group_default_iam_role_arn 46 | node_group_default_iam_role_name = dependency.aws-base.outputs.node_group_default_iam_role_name 47 | helm_charts_path = "${get_terragrunt_dir()}/../../../../helm-charts" 48 | } 49 | -------------------------------------------------------------------------------- /.chglog/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this 6 | project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | {{ if .Versions -}} 9 | 10 | ## [Unreleased] 11 | {{ if .Unreleased.CommitGroups -}} 12 | {{ range .Unreleased.CommitGroups -}} 13 | {{ .Title }}: 14 | {{ range .Commits -}} 15 | {{- if .Subject -}} 16 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject | upperFirst }} 17 | {{ end -}} 18 | {{ end }} 19 | {{ end -}} 20 | {{ else }} 21 | {{ range .Unreleased.Commits -}} 22 | {{- if .Subject -}} 23 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject | upperFirst}} 24 | {{ end -}} 25 | {{ end }} 26 | {{ end -}} 27 | 28 | {{- if .Unreleased.NoteGroups -}} 29 | {{ range .Unreleased.NoteGroups -}} 30 | {{ .Title }}: 31 | {{ range .Notes -}} 32 | - {{ .Body }} 33 | {{ end }} 34 | {{ end -}} 35 | {{ end -}} 36 | {{ end -}} 37 | 38 | {{ range .Versions }} 39 | {{ if ne .Tag.Name "v1.0.0" }} 40 | 41 | 42 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} 43 | {{ if .CommitGroups -}} 44 | {{ range .CommitGroups -}} 45 | {{ .Title }}: 46 | {{ range .Commits -}} 47 | {{- if .Subject -}} 48 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject | upperFirst }} 49 | {{ end -}} 50 | {{ end }} 51 | {{ end -}} 52 | {{ else }} 53 | {{ range .Commits -}} 54 | {{- if .Subject -}} 55 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject | upperFirst }} 56 | {{ end -}} 57 | {{ end }} 58 | {{ end -}} 59 | 60 | {{- if .NoteGroups -}} 61 | {{ range .NoteGroups -}} 62 | {{ .Title }}: 63 | {{ range .Notes -}} 64 | - {{ .Body }} 65 | {{ end }} 66 | {{ end -}} 67 | {{ end -}} 68 | {{ end -}} 69 | {{ end -}} 70 | 71 | {{- if .Versions }} 72 | [Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD 73 | {{ range .Versions -}} 74 | {{ if .Tag.Previous -}} 75 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} 76 | {{ end -}} 77 | {{ end -}} 78 | {{ end -}} 79 | -------------------------------------------------------------------------------- /terraform/layer2-k8s/eks-prometheus-operator-crds.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | kube_prometheus_stack_operator_crds = [ 3 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-alertmanagerconfigs.yaml", 4 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-alertmanagers.yaml", 5 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-podmonitors.yaml", 6 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-probes.yaml", 7 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-prometheuses.yaml", 8 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-prometheusrules.yaml", 9 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-servicemonitors.yaml", 10 | "https://raw.githubusercontent.com/prometheus-community/helm-charts/kube-prometheus-stack-${local.kube_prometheus_stack.chart_version}/charts/kube-prometheus-stack/crds/crd-thanosrulers.yaml" 11 | ] 12 | } 13 | 14 | data "http" "kube_prometheus_stack_operator_crds" { 15 | for_each = (local.victoria_metrics_k8s_stack.enabled || local.kube_prometheus_stack.enabled) ? toset(local.kube_prometheus_stack_operator_crds) : [] 16 | url = each.key 17 | } 18 | 19 | resource "kubectl_manifest" "kube_prometheus_stack_operator_crds" { 20 | for_each = (local.victoria_metrics_k8s_stack.enabled || local.kube_prometheus_stack.enabled) ? { for k, v in data.http.kube_prometheus_stack_operator_crds : yamldecode(v.body).metadata.name => v.body } : {} 21 | yaml_body = each.value 22 | server_side_apply = true 23 | } 24 | -------------------------------------------------------------------------------- /terraform/modules/aws-wafv2-top-10-owasp-rules/README.md: -------------------------------------------------------------------------------- 1 | There are 2 implementations of AWS WAF: AWS WAF Classic and AWS WAFv2. AWS recommends using AWS WAFv2 for new installations. 2 | This terraform module creates AWS WAFv2 rule-group with rules that cover *OWASP TOP 10 security issues* (https://d0.awsstatic.com/whitepapers/Security/aws-waf-owasp.pdf). 3 | 4 | For a CloudFront distribution, AWS WAF is available globally, but you must use the Region US East (N. Virginia) for all of your work. You must create your web ACL using the Region US East (N. Virginia). You must also use this Region to create any other resources that you use in your web ACL, like rule groups, IP sets, and regex pattern sets. 5 | 6 | Example of using this module: 7 | ```bash 8 | module "wafv2_owasp_top_10_rules" { 9 | source = "../modules/aws-wafv2-top-10-owasp-rules" 10 | 11 | name = "${var.name}-${local.env}" 12 | 13 | waf_scope = "CLOUDFRONT" 14 | 15 | max_expected_uri_size = "512" 16 | max_expected_query_string_size = "1024" 17 | max_expected_body_size = "4096" 18 | max_expected_cookie_size = "4093" 19 | 20 | csrf_expected_header = "x-csrf-token" 21 | csrf_expected_size = "36" 22 | 23 | cloudwatch_metrics_enabled = true 24 | blacklisted_cidrs = ["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"] 25 | } 26 | 27 | resource "aws_wafv2_web_acl" "example" { 28 | name = "${var.name}-${local.env}-webacl" 29 | scope = "CLOUDFRONT" 30 | 31 | default_action { 32 | allow {} 33 | } 34 | 35 | rule { 36 | name = "owasp_top10_rules" 37 | priority = 1 38 | 39 | override_action { 40 | none {} 41 | } 42 | 43 | statement { 44 | rule_group_reference_statement { 45 | arn = module.wafv2_owasp_top_10_rules.rule_group_arn 46 | } 47 | } 48 | 49 | visibility_config { 50 | cloudwatch_metrics_enabled = true 51 | metric_name = "owasp-top10-security-issues" 52 | sampled_requests_enabled = true 53 | } 54 | } 55 | 56 | visibility_config { 57 | cloudwatch_metrics_enabled = true 58 | metric_name = "${var.name}-${local.env}-webacl" 59 | sampled_requests_enabled = false 60 | } 61 | } 62 | 63 | resource "aws_cloudfront_distribution" "example" { 64 | ... 65 | web_acl_id = aws_wafv2_web_acl.example.arn 66 | ... 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /helm-charts/postgresql-backups/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "postgresql-backups.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "postgresql-backups.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "postgresql-backups.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "postgresql-backups.labels" -}} 37 | helm.sh/chart: {{ include "postgresql-backups.chart" . }} 38 | {{ include "postgresql-backups.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "postgresql-backups.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "postgresql-backups.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "postgresql-backups.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "postgresql-backups.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | 64 | {{- define "scheduler.jobname" -}} 65 | {{- $name := include "postgresql-backups.fullname" . | trunc 55 | trimSuffix "-" -}} 66 | {{- printf "%s-%s" $name "scheduler" | trunc 63 | trimSuffix "-" -}} 67 | {{- end -}} 68 | -------------------------------------------------------------------------------- /docker/postgresql-exporter-script/pg_exporter_user.sql: -------------------------------------------------------------------------------- 1 | -- To use IF statements, hence to be able to check if the user exists before 2 | -- attempting creation, we need to switch to procedural SQL (PL/pgSQL) 3 | -- instead of standard SQL. 4 | -- More: https://www.postgresql.org/docs/9.3/plpgsql-overview.html 5 | -- To preserve compatibility with <9.0, DO blocks are not used; instead, 6 | -- a function is created and dropped. 7 | CREATE OR REPLACE FUNCTION __tmp_create_user() returns void as $$ 8 | BEGIN 9 | IF NOT EXISTS ( 10 | SELECT -- SELECT list can stay empty for this 11 | FROM pg_catalog.pg_user 12 | WHERE usename = 'postgres_exporter') THEN 13 | CREATE USER postgres_exporter; 14 | END IF; 15 | END; 16 | $$ language plpgsql; 17 | 18 | SELECT __tmp_create_user(); 19 | DROP FUNCTION __tmp_create_user(); 20 | 21 | ALTER USER postgres_exporter WITH PASSWORD :'generate_pass'; 22 | ALTER USER postgres_exporter SET SEARCH_PATH TO postgres_exporter,pg_catalog; 23 | 24 | -- If deploying as non-superuser (for example in AWS RDS), uncomment the GRANT 25 | -- line below and replace with your root user. 26 | -- GRANT postgres_exporter TO ; 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 = <