Service · AWS · Terraform · Kubernetes · CI/CD · DORA

Cloud infrastructure and DevOps

I take ownership of your infrastructure and everything I touch ends up as code in your repositories.

What it usually looks like at the start

  • Deploys go out from one person's laptop, and that person is away next week
  • The AWS console has resources in it that nobody remembers creating, and the bill reflects that
  • There are backups. Nobody has ever restored one, so nobody actually knows
  • An enterprise customer sent a security questionnaire and it has been open for two weeks
  • Monitoring is a customer emailing to say the site is down

What I do about it

Infrastructure as code. Your AWS setup written in Terraform: modular, parameterised, reviewable in a pull request like any other change. I also maintain CloudFormation-based infrastructures, because plenty of them exist and rewriting is not always worth it.

Compute sized to the need. ECS on Fargate for the simple start, self-managed k3s or EKS when the workload calls for Kubernetes. Hardened workloads either way: non-root containers, read-only filesystems, default-deny network policies. The full comparison is below, and the trade-offs get documented whichever direction we pick.

CI/CD with security gates. GitHub Actions pipelines that test, build, scan, and refuse to deploy images with critical vulnerabilities. CI credentials scoped to specific resources, so a leak is an inconvenience rather than an incident.

Monitoring you own. Prometheus, Grafana, Loki and Tempo, self-hosted so logs stay in your VPC. Alert rules defined as code, AWS budgets with spending alerts, and notifications for incidents and cost thresholds delivered on whatever channel you use (email, Slack, SMS) and routed to a person who answers.

Backups that are tested. Scheduled encrypted backups, retention policies, and a job that restores them on a schedule and tells you if it failed. Otherwise "we have backups" is a belief, not a fact.

DNS and mail configuration. Domain records managed properly, as code where the provider allows it, and mail set up the right way: DKIM, SPF and DMARC configured and monitored, so transactional and team email actually arrives.

DORA readiness. I support a DORA-regulated production infrastructure today: controls mapped article by article, incidents classified in the logs, evidence produced by the platform instead of assembled afterwards. If you are in scope, you are not the first one I have seen.

Fargate or Kubernetes?

Both are on the table, and the answer depends on the workload rather than on which one is more interesting to build.

ECS on Fargate

The right start for one normal web application running only on AWS. There are no nodes to patch and no cluster to operate: AWS runs the containers and you pay per task. CloudWatch covers monitoring, deploys stay simple, and the operational burden is much smaller. The limits: task definitions tie you to AWS, and you give up low-level control over the runtime.

Self-managed Kubernetes (k3s)

It earns its complexity when:

  • Portability matters. Standard Kubernetes objects, Helm charts, operators and GitOps tooling move to another cloud, bare metal or on-premise far more easily than ECS definitions.
  • You need operators, CRDs or complex Helm-based applications.
  • You run several small clusters and want to avoid the per-cluster EKS control-plane fee.
  • You need low-level node control: OS and kernel settings, upgrade timing, ingress and storage components, Spot instance strategy.
  • The same stack must also run outside AWS: hybrid or on-premise.

k3s is not inherently less suitable for production. It supports HA with multiple server nodes and either embedded etcd or an external datastore. The difference is who operates that control plane: quorum, backups, upgrades, monitoring, recovery, host failures, networking. In the infrastructures I run, that is me, and it is exactly what the ongoing-operations model covers.

EKS

For a business-critical application that specifically requires Kubernetes, a managed service like EKS is generally lower operational risk than self-managed k3s, in exchange for additional cost. Generally, not always. AWS manages the control plane; it does not make your worker nodes, IAM, networking, deployments, databases or application architecture reliable. Data-plane reliability stays a shared responsibility, and a badly configured EKS environment still fails.

I will tell you which of the three your workload actually needs, and it is often the simpler one. What it costs and how long it takes depends on the application, the migration work, the pipeline, and the networking, security and observability requirements. That is what the estimate is for, rather than a number in a sentence like this one.

In production: a regulated platform

The clearest thing I can show you is an infrastructure I support today: an EU platform regulated under DORA, built and run entirely as code. DORA, the EU's Digital Operational Resilience Act, has applied to financial entities since January 2025 and obliges them to evidence encryption, audit trails, incident detection, backup testing and third-party risk controls.

  • RPO ≤ 4h
  • RTO 4-8h, rebuildable from code
  • Restore verification: weekly, automated
  • 0 open SSH ports
  • CI blocks critical CVEs
  • 24+ alert rules as code

What it looks like

  • Everything as code. Modular Terraform with a live/modules split: reusable modules, one thin composition root per environment. Adding staging means a new directory, not a fork. Remote state lives in a versioned, encrypted S3 bucket with native locking.
  • Kubernetes, self-managed. K3s, a CNCF-certified distribution, on EC2, at a scale where a managed control plane isn't justified. Workers run in an auto-scaling group driven by cluster-autoscaler.
  • A network built for inspection. The databases sit in subnets with no internet route, so they are unreachable from the internet by routing, not just by firewall rules. Ingress is ports 80 and 443 from the load balancer's security group only. Egress is a short, explicit list of protocols.
  • No SSH. Access goes through AWS SSM Session Manager only, and every session is logged in CloudTrail. Port 22 is closed across the infrastructure.
  • Two databases, one module. Aurora PostgreSQL Serverless v2, instantiated twice from the same Terraform module. The application database gets read replicas; the double-entry ledger gets none, because it's write-heavy and replicas would add cost without benefit. TLS is enforced server-side, so a misconfigured client fails loudly.
  • Hardened workloads. Non-root containers, read-only root filesystems, all capabilities dropped, default-deny network policies, resource quotas, and PodDisruptionBudgets configured so routine node drains don't turn into outages.

Backups that prove themselves

Aurora continuous backups with point-in-time recovery. Encrypted logical backups to S3 every 4 hours, versioned and lifecycle-archived. A weekly, fully automated restore verification job running against the real backup artifacts, and the whole infrastructure reconstructible from Terraform. Resulting objectives: RPO ≤ 4 hours, RTO 4-8 hours for full platform reconstruction.

CI/CD and observability

GitHub Actions with path filtering, so only changed components rebuild. Images are scanned on push, and the pipeline fails on any critical finding: the deploy does not proceed. Monitoring is self-hosted Prometheus, Loki, Tempo and Grafana; logs stay inside the VPC, which matters when they contain personal data under GDPR. All 24+ alert rules are defined as code.

The application writes structured audit records tagged for DORA, and Grafana queries them directly. Reportable ICT incidents are queryable the moment they happen instead of being assembled for the regulator after the fact.

DORA areas and their implementation
DORA areaImplementation
ICT risk management (Art. 5-15)IaC-defined controls, reviewable and diffable in version control
Incident detection and handling (Art. 17)Structured audit stream with DORA classification tags; Grafana rules alerting on it
Incident reporting (Art. 19)Severity and service-affecting attributes make reportable incidents directly queryable
Resilience testing (Art. 24-27)Automated weekly restore verification; scan-on-push gating in CI
Third-party risk (Art. 28)Dedicated incident classification for provider failures
Record keepingRetention of the audit stream in versioned, encrypted object storage

Identifiers, account numbers, domains and bucket names genericised here.

Also built and operated: self-hosted mail

For teams that need to own their email, whether for data residency, compliance, or a seat count where SaaS pricing stops making sense, I build and operate a containerized mail and identity stack: Postfix and Dovecot, Rspamd and ClamAV, DKIM, SPF and DMARC configured and monitored, one user directory for mail and internal services, and Grafana dashboards over all of it. Self-hosted email is an operations commitment. That is why it exists as an operated system, and why it pairs naturally with the ongoing-operations model.

Tell me what you are running.

A few lines about what you have and what is going wrong is enough to start. I answer within a business day, and then we set up a call.