diff --git a/bank42/argocd-application.tf b/bank42/argocd-application.tf new file mode 100644 index 0000000..d38c504 --- /dev/null +++ b/bank42/argocd-application.tf @@ -0,0 +1,40 @@ +# ArgoCD Application Resource +# This manages the bank-app application in ArgoCD + +resource "kubectl_manifest" "argocd_application" { + yaml_body = <<-YAML + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + name: ${var.app_name} + namespace: argocd + spec: + project: default + + # Source - GitHub repository + source: + repoURL: ${var.repo_url} + targetRevision: ${var.target_revision} + path: ${var.manifest_path} + + # Destination - EKS cluster + destination: + server: https://kubernetes.default.svc + namespace: ${var.destination_namespace} + + # Sync policy - Automatic with self-heal + syncPolicy: + automated: + prune: true # Delete resources that are no longer in Git + selfHeal: true # Auto-sync when cluster state drifts from Git + allowEmpty: false + syncOptions: + - CreateNamespace=true + retry: + limit: 5 + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + YAML +} diff --git a/bank42/backend.tf b/bank42/backend.tf new file mode 100644 index 0000000..e69de29 diff --git a/bank42/outputs.tf b/bank42/outputs.tf new file mode 100644 index 0000000..9244aaa --- /dev/null +++ b/bank42/outputs.tf @@ -0,0 +1,24 @@ +output "argocd_application_name" { + description = "Name of the ArgoCD application" + value = var.app_name +} + +output "argocd_ui_url" { + description = "URL to access ArgoCD UI (via port-forward)" + value = "http://localhost:8080" +} + +output "github_repo" { + description = "GitHub repository being synced" + value = var.repo_url +} + +output "manifest_path" { + description = "Path in repository being synced" + value = var.manifest_path +} + +output "deployment_namespace" { + description = "Kubernetes namespace where app is deployed" + value = var.destination_namespace +} \ No newline at end of file diff --git a/bank42/provider.tf b/bank42/provider.tf new file mode 100644 index 0000000..1e03ef0 --- /dev/null +++ b/bank42/provider.tf @@ -0,0 +1,23 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.23" + } + kubectl = { + source = "gavinbunney/kubectl" + version = "~> 1.14" + } + } +} + +# Configure Kubernetes provider to use the EKS cluster +provider "kubernetes" { + config_path = "~/.kube/config" +} + +provider "kubectl" { + config_path = "~/.kube/config" +} diff --git a/bank42/readme.md b/bank42/readme.md new file mode 100644 index 0000000..e6ed275 --- /dev/null +++ b/bank42/readme.md @@ -0,0 +1,177 @@ +# Bank 42 - Task 3.2.2: GitOps Configuration with ArgoCD + +This folder contains Terraform configuration for managing ArgoCD applications that sync Kubernetes manifests from GitHub. + +## Overview + +**Task**: Configure GitOps tool (ArgoCD) to sync from the kubernetes-manifests repository + +**Components**: +- ArgoCD is installed in the `dev-test-eks` EKS cluster +- ArgoCD Application syncs manifests from: `https://github.com/pod4-devops/bank-kubernetes-manifest` +- Manifest path: `bank-57-automation` +- Automatic sync with prune and self-heal enabled + +## Prerequisites + +1. AWS CLI configured with `devops-test-user` profile +2. kubectl configured to connect to `dev-test-eks` cluster +3. ArgoCD already installed in the cluster (in `argocd` namespace) +4. Access to the GitHub repository + +## Files + +- **`provider.tf`** - Kubernetes and kubectl provider configuration +- **`argocd-application.tf`** - ArgoCD Application resource definition +- **`variables.tf`** - Input variables for configuration +- **`backend.tf`** - S3 backend for Terraform state +- **`outputs.tf`** - Output values after deployment + +## Setup Instructions + +### 1. Set AWS Profile + +```bash +export AWS_PROFILE=devops-test-user +``` + +### 2. Initialize Terraform + +```bash +cd ~/TerraformProjects/bank-infra/bank42 +terraform init +``` + +### 3. Review the Plan + +```bash +terraform plan +``` + +### 4. Apply Configuration + +```bash +terraform apply +``` + +This will create the ArgoCD Application resource that syncs your manifests. + +## Accessing ArgoCD UI + +### 1. Port Forward to ArgoCD Server + +```bash +kubectl port-forward service/argocd-server -n argocd 8080:443 +``` + +### 2. Get Admin Password + +```bash +kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d +``` + +### 3. Open Browser + +Navigate to: `http://localhost:8080` + +**Login credentials**: +- Username: `admin` +- Password: (from step 2) + +## How GitOps Works + +1. **Developer pushes code** to the GitHub repository +2. **ArgoCD detects changes** (every 3 minutes by default) +3. **ArgoCD syncs automatically** with the cluster +4. **Self-heal enabled** - if someone manually changes the cluster, ArgoCD reverts it back to Git state +5. **Prune enabled** - if you delete something from Git, ArgoCD deletes it from the cluster + +## Application Details + +- **Application Name**: `bank-app` +- **Source Repository**: `https://github.com/pod4-devops/bank-kubernetes-manifest` +- **Target Branch**: `HEAD` (main/master) +- **Manifest Path**: `bank-57-automation` +- **Destination Namespace**: `default` +- **Sync Policy**: Automatic (prune + self-heal) + +## Manifests Being Deployed + +The `bank-57-automation` folder contains: +- `backendapi.yaml` - Backend API deployment +- `frontend.yaml` - Frontend deployment +- `bankend-service.yaml` - Backend service +- `frontend-service.yaml` - Frontend service +- `backend-ingress.yaml` - Ingress configuration +- `configmap.yaml` - Configuration +- `secret.yaml` - Secrets +- `alertmanager-config.yaml` - Monitoring +- `prometheus-rules.yaml` - Prometheus rules + +## Verification + +### Check ArgoCD Application Status + +```bash +kubectl get application -n argocd +``` + +### Check Deployed Resources + +```bash +kubectl get all -n default +``` + +### View ArgoCD Logs + +```bash +kubectl logs -n argocd deployment/argocd-server +``` + +## Troubleshooting + +### Application Not Syncing + +1. Check ArgoCD application status: + ```bash + kubectl describe application bank-app -n argocd + ``` + +2. Check if ArgoCD can access GitHub: + ```bash + kubectl logs -n argocd deployment/argocd-repo-server + ``` + +### Authentication Issues + +If you get "server has asked for client to provide credentials": + +```bash +# Make sure you're using the right AWS profile +export AWS_PROFILE=devops-test-user + +# Update kubeconfig +aws eks update-kubeconfig --name dev-test-eks --region us-east-1 +``` + +## Cleanup + +To remove the ArgoCD application (but keep ArgoCD itself): + +```bash +terraform destroy +``` + +## Notes + +- ArgoCD was installed using Helm (not Terraform) - see installation commands in team documentation +- This Terraform configuration only manages the ArgoCD Application resource +- State is stored in S3: `s3://digitalwitchngbucketcloud1/digitalwitchng/bank42/terraform.tfstate` + +## Next Steps + +After completing this task, you can: +1. Add more applications to ArgoCD +2. Configure notifications for sync events +3. Set up RBAC for team members +4. Integrate with CI/CD pipeline for automated deployments diff --git a/bank42/variables.tf b/bank42/variables.tf new file mode 100644 index 0000000..74fdfc0 --- /dev/null +++ b/bank42/variables.tf @@ -0,0 +1,41 @@ +variable "app_name" { + description = "Name of the ArgoCD application" + type = string + default = "bank-app" +} + +variable "repo_url" { + description = "GitHub repository URL containing Kubernetes manifests" + type = string + default = "https://github.com/pod4-devops/bank-kubernetes-manifest" +} + +variable "target_revision" { + description = "Git branch, tag, or commit to sync from" + type = string + default = "HEAD" +} + +variable "manifest_path" { + description = "Path within the repository containing the manifests" + type = string + default = "bank-57-automation" +} + +variable "destination_namespace" { + description = "Kubernetes namespace where the application will be deployed" + type = string + default = "default" +} + +variable "cluster_name" { + description = "EKS cluster name" + type = string + default = "dev-test-eks" +} + +variable "aws_region" { + description = "AWS region where the EKS cluster is located" + type = string + default = "us-east-1" +} \ No newline at end of file diff --git a/bank46/terraform/irsa/data.tf b/bank46/terraform/irsa/data.tf new file mode 100644 index 0000000..6349c40 --- /dev/null +++ b/bank46/terraform/irsa/data.tf @@ -0,0 +1,9 @@ +# Get information about the EKS cluster +data "aws_eks_cluster" "selected" { + name = var.cluster_name +} + +# Get the OIDC provider URL from the cluster +data "aws_eks_cluster_auth" "selected" { + name = var.cluster_name +} diff --git a/bank46/terraform/irsa/iam-policy.tf b/bank46/terraform/irsa/iam-policy.tf new file mode 100644 index 0000000..c9b0cfb --- /dev/null +++ b/bank46/terraform/irsa/iam-policy.tf @@ -0,0 +1,32 @@ +# IAM Policy for Secrets Manager and SSM Parameter Store access +resource "aws_iam_policy" "secret_access" { + name = "Bank46-SecretAccess-Policy" + description = "Policy for Bank46 project to access Secrets Manager and Parameter Store" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret", + "ssm:GetParameters", + "ssm:GetParameter", + "ssm:DescribeParameters" + ] + Resource = "*" + } + ] + }) + + tags = { + Project = "Bank46" + Environment = var.environment + ManagedBy = "Terraform" + } +} + +output "policy_arn" { + value = aws_iam_policy.secret_access.arn +} diff --git a/bank46/terraform/irsa/iam-role.tf b/bank46/terraform/irsa/iam-role.tf new file mode 100644 index 0000000..aa83a71 --- /dev/null +++ b/bank46/terraform/irsa/iam-role.tf @@ -0,0 +1,47 @@ +# Create IAM Role for IRSA +resource "aws_iam_role" "secret_access" { + name = "Bank46-SecretAccess-Role" + description = "IAM Role for Bank46 pods to access secrets via IRSA" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Federated = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${local.oidc_provider}" + } + Action = "sts:AssumeRoleWithWebIdentity" + Condition = { + StringEquals = { + "${local.oidc_provider}:sub": "system:serviceaccount:${var.namespace}:${var.service_account_name}" + "${local.oidc_provider}:aud": "sts.amazonaws.com" + } + } + } + ] + }) + + tags = { + Project = "Bank46" + Environment = var.environment + ManagedBy = "Terraform" + } +} + +# Get current AWS account ID +data "aws_caller_identity" "current" {} + +# Attach the policy to the role +resource "aws_iam_role_policy_attachment" "secret_access" { + role = aws_iam_role.secret_access.name + policy_arn = aws_iam_policy.secret_access.arn +} + +output "role_arn" { + value = aws_iam_role.secret_access.arn +} + +output "role_name" { + value = aws_iam_role.secret_access.name +} diff --git a/bank46/terraform/irsa/kubernetes-service-account.tf.backup b/bank46/terraform/irsa/kubernetes-service-account.tf.backup new file mode 100644 index 0000000..d117a84 --- /dev/null +++ b/bank46/terraform/irsa/kubernetes-service-account.tf.backup @@ -0,0 +1,31 @@ +# Kubernetes Provider (using the cluster we discovered) +provider "kubernetes" { + host = data.aws_eks_cluster.selected.endpoint + cluster_ca_certificate = base64decode(data.aws_eks_cluster.selected.certificate_authority[0].data) + token = data.aws_eks_cluster_auth.selected.token +} + +# Create Kubernetes Service Account +resource "kubernetes_service_account" "secret_access" { + metadata { + name = var.service_account_name + namespace = var.namespace + annotations = { + "eks.amazonaws.com/role-arn" = aws_iam_role.secret_access.arn + } + labels = { + app = "bank46" + component = "secret-access" + } + } + + automount_service_account_token = true +} + +output "service_account_name" { + value = kubernetes_service_account.secret_access.metadata[0].name +} + +output "service_account_namespace" { + value = kubernetes_service_account.secret_access.metadata[0].namespace +} diff --git a/bank46/terraform/irsa/oidc.tf b/bank46/terraform/irsa/oidc.tf new file mode 100644 index 0000000..4847455 --- /dev/null +++ b/bank46/terraform/irsa/oidc.tf @@ -0,0 +1,17 @@ +# Extract the OIDC provider URL +locals { + oidc_provider = replace(data.aws_eks_cluster.selected.identity[0].oidc[0].issuer, "https://", "") +} + +# Output the OIDC URL for verification +output "oidc_provider_url" { + value = local.oidc_provider +} + +output "cluster_name" { + value = var.cluster_name +} + +output "aws_account_id" { + value = data.aws_caller_identity.current.account_id +} diff --git a/bank46/terraform/irsa/provider.tf b/bank46/terraform/irsa/provider.tf new file mode 100644 index 0000000..ff37ea0 --- /dev/null +++ b/bank46/terraform/irsa/provider.tf @@ -0,0 +1,22 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = "us-east-1" + + default_tags { + tags = { + Project = "Bank46" + Environment = "Dev" + Terraform = "true" + } + } +} diff --git a/bank46/terraform/irsa/service-account.yaml b/bank46/terraform/irsa/service-account.yaml new file mode 100644 index 0000000..cf6c081 --- /dev/null +++ b/bank46/terraform/irsa/service-account.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bank46-secret-sa + namespace: default + annotations: + eks.amazonaws.com/role-arn: arn:aws:iam::245000192780:role/Bank46-SecretAccess-Role + labels: + app: bank46 + component: secret-access diff --git a/bank46/terraform/irsa/variables.tf b/bank46/terraform/irsa/variables.tf new file mode 100644 index 0000000..eb7b76a --- /dev/null +++ b/bank46/terraform/irsa/variables.tf @@ -0,0 +1,29 @@ +variable "cluster_name" { + description = "Name of the EKS cluster" + type = string + default = "bank24-eks-cluster" # Using existing cluster +} + +variable "aws_region" { + description = "AWS region" + type = string + default = "us-east-1" +} + +variable "namespace" { + description = "Kubernetes namespace for the service account" + type = string + default = "default" +} + +variable "service_account_name" { + description = "Name of the Kubernetes service account" + type = string + default = "bank46-secret-sa" # Still bank46 for the project +} + +variable "environment" { + description = "Environment name for tagging" + type = string + default = "bank46-dev" +} diff --git a/bank51/alertmanager-pvc.yaml b/bank51/alertmanager-pvc.yaml new file mode 100644 index 0000000..33d36cd --- /dev/null +++ b/bank51/alertmanager-pvc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: prometheus-alertmanager + namespace: monitoring + labels: + app: prometheus + component: alertmanager +spec: + accessModes: + - ReadWriteOnce + storageClassName: prometheus-ebs + resources: + requests: + storage: 5Gi diff --git a/bank51/main.tf b/bank51/main.tf new file mode 100644 index 0000000..6c0d955 --- /dev/null +++ b/bank51/main.tf @@ -0,0 +1,85 @@ +# Create Kubernetes namespace for monitoring +resource "kubernetes_namespace" "monitoring" { + metadata { + name = var.namespace + + labels = { + name = var.namespace + environment = var.environment + } + } +} + +# Create StorageClass for EBS volumes +resource "kubernetes_storage_class" "prometheus_ebs" { + metadata { + name = var.storage_class_name + } + + storage_provisioner = "kubernetes.io/aws-ebs" + + parameters = { + type = "gp3" + encrypted = "true" + } + + reclaim_policy = "Retain" + volume_binding_mode = "WaitForFirstConsumer" + allow_volume_expansion = true + + depends_on = [kubernetes_namespace.monitoring] +} + +# Create PersistentVolumeClaim for Prometheus server +resource "kubernetes_persistent_volume_claim" "prometheus_server" { + metadata { + name = "prometheus-server" + namespace = var.namespace + + labels = { + app = "prometheus" + component = "server" + } + } + + spec { + access_modes = ["ReadWriteOnce"] + + resources { + requests = { + storage = "${var.storage_size_gb}Gi" + } + } + + storage_class_name = var.storage_class_name + } + + depends_on = [kubernetes_storage_class.prometheus_ebs] +} + +# Create PersistentVolumeClaim for Prometheus alertmanager +resource "kubernetes_persistent_volume_claim" "prometheus_alertmanager" { + metadata { + name = "prometheus-alertmanager" + namespace = var.namespace + + labels = { + app = "prometheus" + component = "alertmanager" + } + } + + spec { + access_modes = ["ReadWriteOnce"] + + resources { + requests = { + storage = "5Gi" + } + } + + storage_class_name = var.storage_class_name + } + + depends_on = [kubernetes_storage_class.prometheus_ebs] +} diff --git a/bank51/outputs.tf b/bank51/outputs.tf new file mode 100644 index 0000000..8629bd9 --- /dev/null +++ b/bank51/outputs.tf @@ -0,0 +1,34 @@ +output "namespace_name" { + description = "Name of the monitoring namespace" + value = kubernetes_namespace.monitoring.metadata[0].name +} + +output "storage_class_name" { + description = "Name of the created storage class" + value = kubernetes_storage_class.prometheus_ebs.metadata[0].name +} + +output "prometheus_pvc_name" { + description = "Name of Prometheus server PVC" + value = kubernetes_persistent_volume_claim.prometheus_server.metadata[0].name +} + +output "alertmanager_pvc_name" { + description = "Name of Alertmanager PVC" + value = kubernetes_persistent_volume_claim.prometheus_alertmanager.metadata[0].name +} + +output "storage_size" { + description = "Prometheus storage size" + value = "${var.storage_size_gb}Gi" +} + +output "retention_days" { + description = "Prometheus retention period" + value = "${var.prometheus_retention_days} days" +} + +output "cluster_name" { + description = "EKS cluster name" + value = var.cluster_name +} diff --git a/bank51/prometheus-pvc.yaml b/bank51/prometheus-pvc.yaml new file mode 100644 index 0000000..539cfa3 --- /dev/null +++ b/bank51/prometheus-pvc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: prometheus-server + namespace: monitoring + labels: + app: prometheus + component: server +spec: + accessModes: + - ReadWriteOnce + storageClassName: prometheus-ebs + resources: + requests: + storage: 20Gi diff --git a/bank51/provider.tf b/bank51/provider.tf new file mode 100644 index 0000000..907970e --- /dev/null +++ b/bank51/provider.tf @@ -0,0 +1,48 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.23" + } + helm = { + source = "hashicorp/helm" + version = "~> 2.10" + } + } +} + +provider "aws" { + region = var.aws_region +} + +# Get EKS cluster authentication token +data "aws_eks_cluster_auth" "cluster" { + name = var.cluster_name +} + +# Get EKS cluster details +data "aws_eks_cluster" "cluster" { + name = var.cluster_name +} + +# Configure Kubernetes provider +provider "kubernetes" { + host = data.aws_eks_cluster.cluster.endpoint + cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data) + token = data.aws_eks_cluster_auth.cluster.token +} + +# Configure Helm provider +provider "helm" { + kubernetes { + host = data.aws_eks_cluster.cluster.endpoint + cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data) + token = data.aws_eks_cluster_auth.cluster.token + } +} diff --git a/bank51/terraform.tfvars b/bank51/terraform.tfvars new file mode 100644 index 0000000..ef15ca4 --- /dev/null +++ b/bank51/terraform.tfvars @@ -0,0 +1,7 @@ +aws_region = "us-east-1" +environment = "dev" +cluster_name = "bank24-eks-cluster" +namespace = "monitoring" +storage_class_name = "prometheus-ebs" +prometheus_retention_days = 15 +storage_size_gb = 20 diff --git a/bank51/variables.tf b/bank51/variables.tf new file mode 100644 index 0000000..9ce89bf --- /dev/null +++ b/bank51/variables.tf @@ -0,0 +1,41 @@ +variable "aws_region" { + description = "AWS region" + type = string + default = "us-east-1" +} + +variable "environment" { + description = "Environment name" + type = string + default = "dev" +} + +variable "cluster_name" { + description = "Existing EKS cluster name" + type = string + default = "bank24-eks-cluster" +} + +variable "namespace" { + description = "Kubernetes namespace for Prometheus" + type = string + default = "monitoring" +} + +variable "storage_class_name" { + description = "Name for the storage class" + type = string + default = "prometheus-ebs" +} + +variable "prometheus_retention_days" { + description = "How many days to retain Prometheus metrics" + type = number + default = 15 +} + +variable "storage_size_gb" { + description = "Storage size in GB for Prometheus" + type = number + default = 20 +}