Quick Answer
Use Terraform Enterprise for infrastructure provisioning (EKS clusters, RDS databases, networking) with Sentinel policy enforcement, and ArgoCD for application deployment to Kubernetes. Git repositories are the single source of truth for both layers, with TFE workspaces triggered by infrastructure PRs and ArgoCD syncing application manifests automatically.
Detailed Answer
Think of building and managing a shopping mall. Terraform Enterprise is the construction company that builds the mall itself — the structure, plumbing, electrical, and parking lot. ArgoCD is the property manager that handles the tenants — which stores go where, their signage, operating hours, and inventory. Both work from blueprints (Git), but they manage different layers of the same system. The construction company does not rearrange store displays, and the property manager does not modify load-bearing walls. This separation of concerns is the foundation of managing infrastructure and applications together with GitOps. Terraform Enterprise (TFE) manages the infrastructure layer through workspaces connected to VCS repositories. Each workspace represents a logical infrastructure component: the EKS cluster configuration, the RDS database instances, the VPC and networking setup, the IAM roles and policies. When an engineer pushes a change to the infrastructure repository (for example, adding a new node group to the EKS cluster for the fraud-detector workload), TFE automatically triggers a speculative plan that shows what will change. The plan must pass Sentinel policy checks before it can be applied — policies that enforce requirements like 'all RDS instances must have encryption at rest enabled' or 'no security group can allow ingress from 0.0.0.0/0.' In a banking environment, these Sentinel policies encode PCI-DSS and SOX compliance requirements, turning regulatory mandates into automated, version-controlled code that auditors can review. ArgoCD manages the application layer using the GitOps pattern. Application manifests (Kubernetes Deployments, Services, ConfigMaps, Helm charts) live in Git repositories, and ArgoCD continuously reconciles the cluster state with the desired state in Git. When a developer merges a PR that updates the payments-api image tag from v2.4.0 to v2.5.0, ArgoCD detects the change and syncs the new manifest to the cluster. ArgoCD provides drift detection — if someone manually modifies a resource with kubectl edit, ArgoCD flags it as out-of-sync and can automatically revert the change. This is critical in banking where unauthorized changes must be detected and prevented for compliance. The integration point between TFE and ArgoCD is carefully designed. Terraform provisions the infrastructure and outputs values that applications need — the RDS endpoint for settlements-db, the ElastiCache endpoint for session storage, the IAM role ARN for IRSA (IAM Roles for Service Accounts). These outputs are written to a shared location (AWS SSM Parameter Store, HashiCorp Vault, or a dedicated Git repository) where ArgoCD-managed application manifests can reference them. For example, Terraform creates the RDS instance and writes the endpoint to SSM, and the payments-api Kubernetes manifest uses an ExternalSecret that reads from SSM to inject the database connection string. This avoids hardcoding infrastructure details in application manifests and creates a clean dependency chain. In production at a bank, the workflow looks like this: a platform engineer opens a PR to the infra repository to upgrade the EKS cluster version. TFE runs a speculative plan showing the rolling node replacement strategy. Sentinel policies verify the upgrade path is supported and that the new version does not remove any APIs used by deployed applications. A senior engineer reviews and approves the PR. TFE applies the change during a maintenance window (configured via workspace run schedules). After the infrastructure change completes, the application team updates their manifests if needed (for example, updating API versions for deprecated resources), and ArgoCD syncs the changes. Both the TFE apply log and the ArgoCD sync history provide complete audit trails that compliance can review during examinations. The biggest gotcha is circular dependencies between infrastructure and application changes. If your Terraform code creates a Kubernetes namespace and ArgoCD tries to deploy to that namespace before Terraform finishes, the sync fails. Use ArgoCD sync waves and health checks to handle ordering — infrastructure-level resources (namespaces, CRDs, service accounts) deploy in wave 0, and applications deploy in wave 1 after health checks confirm the prerequisites exist. Another gotcha is state file security in TFE — state files contain sensitive information like database passwords and should be encrypted, access-controlled, and never stored in Git. Finally, avoid the temptation to manage everything in Terraform — Kubernetes resources that change frequently (Deployments, ConfigMaps) belong in ArgoCD, while resources that change rarely (VPCs, EKS clusters, RDS) belong in Terraform.
Code Example
# Terraform Enterprise workspace configuration
# infra/terraform-cloud.tf
terraform {
cloud {
organization = "bank-platform"
workspaces {
name = "banking-eks-production"
}
}
}
# EKS cluster provisioned by Terraform Enterprise
module "eks" {
source = "app.terraform.io/bank-platform/eks-cluster/aws"
version = "3.2.0" # Private registry module, version-controlled
cluster_name = "banking-production"
cluster_version = "1.29"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
node_groups = {
payments = {
instance_types = ["m6i.2xlarge"]
desired_size = 6
labels = { workload = "payments" }
}
}
}
# Output infrastructure values for ArgoCD-managed apps
resource "aws_ssm_parameter" "settlements_db_endpoint" {
name = "/banking/prod/settlements-db/endpoint"
type = "SecureString"
value = module.settlements_db.endpoint
}
resource "aws_ssm_parameter" "eks_cluster_endpoint" {
name = "/banking/prod/eks/endpoint"
type = "SecureString"
value = module.eks.cluster_endpoint
}
---
# Sentinel policy - enforce PCI-DSS compliance
# policies/pci-dss-rds.sentinel
import "tfplan/v2" as tfplan
# All RDS instances must have encryption at rest
rds_instances = filter tfplan.resource_changes as _, rc {
rc.type is "aws_db_instance" and
rc.change.actions contains "create"
}
encryption_enforced = rule {
all rds_instances as _, instance {
instance.change.after.storage_encrypted is true
}
}
# All RDS instances must have audit logging enabled
audit_logging = rule {
all rds_instances as _, instance {
instance.change.after.enabled_cloudwatch_logs_exports contains "audit"
}
}
main = rule {
encryption_enforced and audit_logging
}
---
# ArgoCD Application for payments-api (synced from Git)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payments-api
namespace: argocd
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: platform-deploys
notifications.argoproj.io/subscribe.on-sync-failed.slack: platform-alerts
spec:
project: banking-production
source:
repoURL: https://github.com/bank/application-manifests.git
targetRevision: main
path: apps/payments-api/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: banking-prod
syncPolicy:
automated:
prune: true # Remove resources deleted from Git
selfHeal: true # Revert manual kubectl changes
syncOptions:
- CreateNamespace=false # Namespace managed by Terraform
retry:
limit: 3
backoff:
duration: 30s
maxDuration: 3m
---
# ExternalSecret - bridge between TFE outputs and ArgoCD apps
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: settlements-db-credentials
namespace: banking-prod
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-parameter-store
kind: ClusterSecretStore
target:
name: settlements-db-connection
data:
- secretKey: endpoint
remoteRef:
key: /banking/prod/settlements-db/endpoint
- secretKey: password
remoteRef:
key: /banking/prod/settlements-db/password◈ Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐ │ GitOps: Terraform Enterprise + ArgoCD │ │ │ │ ┌─────────────────────┐ ┌─────────────────────────────┐ │ │ │ Infrastructure │ │ Application Layer │ │ │ │ Git Repository │ │ Git Repository │ │ │ │ │ │ │ │ │ │ VPC, EKS, RDS, │ │ Deployments, Services, │ │ │ │ IAM, S3 configs │ │ ConfigMaps, Helm charts │ │ │ └──────────┬──────────┘ └──────────────┬──────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────────────┐ ┌──────────────────────────┐ │ │ │ Terraform Enterprise │ │ ArgoCD │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ ┌────────────────────┐ │ │ │ │ │ Sentinel Policy │ │ │ │ Drift Detection │ │ │ │ │ │ (PCI-DSS/SOX) │ │ │ │ + Self-Heal │ │ │ │ │ └──────────────────┘ │ │ └────────────────────┘ │ │ │ │ ┌──────────────────┐ │ │ ┌────────────────────┐ │ │ │ │ │ Plan → Approve │ │ │ │ Sync Waves: │ │ │ │ │ │ → Apply │ │ │ │ 0: CRDs/Namespaces │ │ │ │ │ └──────────────────┘ │ │ │ 1: Applications │ │ │ │ └───────────┬──────────┘ │ └────────────────────┘ │ │ │ │ └─────────────┬────────────┘ │ │ │ Outputs (SSM/Vault) │ │ │ └──────────────┬─────────────────┘ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ ExternalSecrets: Bridge infra outputs → app configs │ │ │ │ TFE writes DB endpoint → SSM → ExternalSecret → Pod │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Audit Trail: TFE apply logs + ArgoCD sync history │ │ │ │ → Complete change record for regulatory examination │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘