GH GambleHub

Infrastructure as Code: Terraform, Ansible

Infrastructure as Code: Terraform, Ansible

1) Why IaC and how tools differ

Terraform - declarative orchestrator-IaC: creates/modifies cloud infrastructure (VPC, K8s, LB, DB, IAM) through providers. Manages resource lifecycle and stores state.
Ansible - procedural config-IaC and configuration management: configures hosts/software (packages, files, services), knows how to provide applications, templating, orchestration of steps. Without an agent (SSH/WinRM), with idempotency of tasks.

Combination: Terraform - "what the platform is made of," Ansible - "how it is configured and launched."

2) Structure of repositories and layers

We recommend 3 layers:

1. Foundation (Landing Zone): networks, IAM, KMS, base logs/monitoring.

2. Platform: Kubernetes clusters, databases, queues, observability stack.

3. Workloads: spaces/namespaces, service accounts, policies, configs.

Repo:
  • 'iac/terraform/' - modules and environments ('modules/',' envs/').
  • 'iac/ansible/' - roles ('roles/'), playbooks (' playbooks/'), inventories ('inventions/').
  • 'policies/' - OPA/Conftest rules.
  • 'pipelines/' - CI/CD scripts (lint/plan/apply/test).

3) Terraform: modules, state, environments

3. 1 Modules

Small, reused: 'vpc', 'eks', 'rds', 'redis', 'alb', 'iam-role'.
Inputs → 'variables. tf ', outputs →' outputs. tf ', versions - through the registry of modules/git-tags.

Example of module call:
hcl module "vpc" {
source = "git::ssh://git@repo/iac. git//modules/vpc? ref=v1. 6. 0"
name  = "prod-core"
cidr  = "10. 0. 0. 0/16"
azs  = ["eu-central-1a","eu-central-1b"]
}

3. 2 State

Remote backend (S3/GCS + DynamoDB/LockTable) + locks.
Separation by environment: 'prod. tfstate`, `staging. tfstate`.
State-drift: 'terraform plan' in CI on schedule; alert when drifting.

Example backend:
hcl terraform {
backend "s3" {
bucket     = "iac-state"
key      = "prod/network/terraform. tfstate"
region     = "eu-central-1"
dynamodb_table = "iac-locks"
encrypt    = true
}
}

3. 3 Workspaces / Envs

Options:
  • Separate directories' envs/prod ',' envs/stage '(visual).
  • Workspaces for light variations, but avoid mixing secrets.
  • Parameters via 'tfvars': 'prod. tfvars`, `stage. tfvars`.

4) Ansible: Roles, Inventories, Idempotence

4. 1 Roles and playbooks

Galaxy standard:

roles/
nginx/
tasks/main. yml templates/.j2 handlers/main. yml defaults/main. yml playbooks/
site. yml
Playbook example:
yaml
- hosts: web become: true roles:
- role: nginx vars:
nginx_listen_port: 8080

4. 2 Inventories and dynamics

`inventories/prod/hosts. yml '+ variables' group _ vars/host _ vars'.
Dynamic inventory: 'aws _ ec2', 'gcp _ compute', 'kubernetes. core`.

4. 3 Idempotency

Use modules (not 'shell') where possible.
'changed _ when '/' check _ mode'for dry runs.
Handlers only reflect on changes.

5) Secrets and configs

Terraform: secretion of values ​ ​ through 'sensitive = true'; the secrets themselves are not in the state (store in AWS Secrets Manager/HashiCorp Vault/KMS and refer to the data source).
Ansible: Vault for variable encryption ('ansible-vault encrypt'), integration with HashiCorp Vault/KMS.
GitOps: secrets in a separate repo/storage, access by least-privilege.

6) Policy as Code

OPA/Conftest for Terraform plans: banning public S3, open SG, untagged resources (tags).
Terraform Cloud/Enterprise - Sentinel as an alternative.
Ansible Lint: style and security (without 'sudo: yes' where not needed, without raw-shell).

Example of Conftest (rego, simplified):
rego package terraform. security

deny[msg] {
input. resource_type == "aws_security_group_rule"
input. values. cidr_blocks[_] == "0. 0. 0. 0/0"
input. values. from_port == 22 msg:= "SSH from 0. 0. 0. 0/0 is forbidden"
}

7) IaC testing

Terraform: 'tflint', 'tfsec '/' checkov', Terratest (Go) for integration checks.
Ansible: 'ansible-lint', Molecule (+ Docker/Podman/EC2) to test roles.
Smoke tests after apply: HTTP probes, port/processes, rights.

8) CI/CD и GitOps

Pipeline (on Pull/Merge Request):

1. Lint/Sec: tflint, tfsec/checkov, ansible-lint.

2. Plan: 'terraform plan' with publication of artifact (comment in MR).

3. Policy Gate: Conftest/Sentinel.

4. Apply (manual/approved): only on main with the signature of artifacts.

5. Ansible deploy: '--check' on stage, then '--diff' in prod.

6. Post-checks: synthetics/Probe, release annotation dashboard.

GitOps:
  • Keep manifestos as a source of truth; Argo CD/Flux for Kubernetes, but basic clusters/primitives through Terraform.

9) Patterns for Kubernetes, networks, databases

9. 1 Kubernetes

Terraform: EKS/GKE/AKS clusters, nodes, IAM, StorageClass, LB.
Ansible: AMI/bastion preparation, image assembly/repositories, post-install (loggers/agents/OTel).

9. 2 Networks and perimeter

Terraform: VPC/subnets/NAT/Transit-Gateway/WAF, routes.
Ansible: NGINX/Envoy/HAProxy config, TLS, WAF rules config.

9. 3 Bases/caches/queues

Terraform: RDS/CloudSQL group parameter, Redis/ElastiCache, Kafka/MSK.
Ansible: cache warm-up, migration jobs, setting up backups/agents.

10) Examples of configs

10. 1 Terraform — RDS PostgreSQL + SG

hcl module "db" {
source        = "terraform-aws-modules/rds/aws"
engine        = "postgres"
engine_version    = "15. 4"
instance_class    = "db. m6g. large"
allocated_storage  = 100 name         = "core"
username       = var. db_user password       = var. db_password # см. secret data source vpc_security_group_ids = [module. db_sg. security_group_id]
multi_az       = true backup_retention   = 7
}

module "db_sg" {
source = "terraform-aws-modules/security-group/aws"
name  = "db-core"
vpc_id = module. vpc. vpc_id ingress_cidr_blocks = ["10. 0. 0. 0/8"]
ingress_rules    = ["postgresql-tcp"]
}

10. 2 Terraform - data source of the secret

hcl data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/db/core"
}
variable "db_password" {
type   = string sensitive = true default  = jsondecode(data. aws_secretsmanager_secret_version. db. secret_string). password
}

10. 3 Ansible - postgresql-client role (fragment)

yaml
- name: Install packages apt:
name: [ "postgresql-client-15" ]
state: present update_cache: yes

- name: Create. pgpass copy:
dest: /home/deploy/.pgpass mode: '0600'
content: "{{ db_host }}:5432:core:{{ db_user }}:{{ db_password }}"
no_log: true

- name: Smoke query shell: psql -h {{ db_host }} -U {{ db_user }} -d core -c "select 1"
register: psql_out changed_when: false

10. 4 Ansible - NGINX with template

yaml
- name: Deploy nginx. conf template:
src: templates/nginx. conf. j2 dest: /etc/nginx/nginx. conf notify: Restart nginx

- name: Ensure nginx running service:
name: nginx state: started enabled: true

handlers:
- name: Restart nginx service: { name: nginx, state: restarted }

11) Drift and compliance management

Periodic 'terraform plan' in read-only key; creates a ticket when there is a discrepancy.
Ansible --check scheduled for critical roles (audit mode).
Reports: failed OPA/Conftest policies, untagged/backup/monitoring resources.

12) Observability and audit

'terraform apply'logs and plan artifacts - save to object storage.
Ansible: 'callback _ plugins' (json) → central log/ELK; include job ID, commit SHA, trace_id.
Metrics: execution time of plans/playbooks, frequency of changes, test coverage.

13) Safety

Module/role signature or fixed tags/hashes.
Minimum IAM rights ('plan' ≠ 'apply'), separate the roles of CI and human app.
Encryption of state/logs, private registers of modules/roles.
Policy "no plaintext secrets in VCS," secret scanners (gitleaks/trufflehog).

14) Anti-patterns

One Terraform monster module "for everything"; missing module versions.
Local'terraform. tfstate 'and no locks.
Manual edits in the cloud over IaC → eternal drift.
Ansible 'shell '/' command' instead of modules (breaks idempotency).
Inventory "in one file" without groups/variables, mixing prod/stage.
Secrets in vars/repositories, absence of Vault/KMS.
Apply without Plan and without Peer Review.

15) Implementation checklist (0-45 days)

0-10 days

Configure remote backend/lock, expand Terraform modules.
Enable tflint/tfsec/checkov, ansible-lint; negotiate resource tags/labels.
Create Ansible roles for NGINX/agents/loggers; organize inventories.

11-25 days

Add Conftest/OPA, Terratest and Molecule for critical modules/roles.
CI: 'plan' on MR, plan artifact, manual-apply with approw; Ansible `--check` на stage.
Integrate Secret Storage (Vault/KMS/Secrets Manager).

26-45 days

Auto schedule for drift detection, policy reports.
Directory of modules/roles with versioning; 'README. md 'in each.
GitOps: annotations of releases, a combination with monitoring and alert gates.

16) Maturity metrics

% of environments with remote state and locks = 100%.
The share of modules/roles with tests (Terratest/Molecule) ≥ 70%.
The average time from MR to apply (prod) is hours, not days.
Zero "manual drift" (all changes go through MR).
100% of critical resources are covered by Policy as Code (tags, encryption, backup).

17) Conclusion

Terraform specifies a predictable, repeatable infrastructure base; Ansible brings hosts and services to the desired state. Add Policy as Code, remote state with location, tests, secret management and CI/CD with plan→review→apply - and your IaC loop becomes manageable, secure and fast, and releases are atomic and reversible.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Telegram
@Gamble_GC
Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.