AWS Peripheries Deployment Guide

Prev Next

This guide walks you through deploying supporting infrastructure components using the kindo-peripheries module.

Table of Contents

  1. Quick Start
  2. Understanding the Peripheries Module
  3. Service Enable/Disable Flags
  4. Core Services Configuration
  5. Feature Flags Management (Unleash)
  6. Secret Management (External Secrets)
  7. Observability Configuration
  8. Advanced Configuration
  9. Deployment Process
  10. Post-Deployment Verification
  11. Troubleshooting

Quick Start

1. Set Up Your Deployment Directory

# Navigate to the peripheries example
cd kindo-modules/examples/kindo-peripheries-standalone
# Create your configuration
cp terraform.tfvars.example terraform.tfvars
# Edit your configuration
vi terraform.tfvars

2. Minimal Configuration

Here’s the absolute minimum you need in terraform.tfvars:

# Core configuration (REQUIRED)
project_name = "mycompany"
environment  = "production"
aws_region   = "us-west-2"

# Essential services (typically all enabled)
enable_alb_ingress      = true  # AWS Load Balancer Controller
enable_external_secrets = true  # Sync secrets from AWS Secrets Manager
enable_unleash          = true  # Feature flags
enable_unleash_edge     = true  # Feature flag edge proxy
enable_external_dns     = true  # Automatic DNS management

# Observability (choose based on your setup)
enable_otel_collector_cr = true  # If using AWS ADOT addon
# OR
# enable_otel_collector = true   # If using standalone OTel

3. Deploy

# Set your AWS profile if using AWS ingress
export AWS_PROFILE=your-aws-profile
# Initialize Terraform
terraform init
# Review the plan
terraform plan
# Deploy
terraform apply

Understanding the Peripheries Module

What the Module Does

The kindo-peripheries module deploys supporting Kubernetes services that Kindo applications depend on:

  1. Traffic Management: ALB Ingress Controller for load balancing
  2. Secret Synchronization: External Secrets Operator for AWS Secrets Manager integration
  3. Feature Flags: Unleash and Unleash Edge for feature management
  4. DNS Management: External DNS for automatic Route53 updates
  5. Observability: OpenTelemetry Collector for metrics and traces
  6. PII Detection: Presidio for data anonymization (optional)

Module Architecture

Infrastructure (EKS, RDS, etc.) ─┐
                                 ├─> Peripheries Module ─> Kubernetes Services
Secrets (AWS Secrets Manager) ───┘                        │
                                                          └─> Ready for Apps

How It Consumes Other Modules

The peripheries module automatically consumes outputs from:

  • Infrastructure Module: IAM roles, cluster info, domain names
  • Secrets Module: Generated tokens and credentials

Service Enable/Disable Flags

Understanding Each Service

Configure which services to deploy in your terraform.tfvars:

# Traffic Management
enable_alb_ingress = true

What this does:

  • Deploys AWS Load Balancer Controller
  • Manages Application Load Balancers for Ingress resources
  • Required for external traffic routing
  • When to disable: Only if using a different ingress controller (nginx, traefik)
# Secret Management
enable_external_secrets = true

What this does:

  • Deploys External Secrets Operator
  • Syncs secrets from AWS Secrets Manager to Kubernetes
  • Creates ClusterSecretStores for app access
  • When to disable: If managing secrets differently (sealed-secrets, vault-injector)
# Feature Flags
enable_unleash      = true
enable_unleash_edge = true

What these do:

  • Unleash: Central feature flag management server
  • Unleash Edge: Edge proxy for faster flag evaluation
  • Enables runtime feature toggling without deployments
  • When to disable: If not using feature flags or using a different system
# DNS Management
enable_external_dns = true

What this does:

  • Automatically creates Route53 records for services
  • Updates DNS when services change
  • Works with annotations on Ingress/Service resources
  • When to disable: If manually managing DNS or using different DNS provider
# Observability
enable_otel_collector_cr = true  # For AWS ADOT
# OR
enable_otel_collector = false    # For standalone

What these do:

  • otel_collector_cr: Creates config for AWS ADOT EKS addon
  • otel_collector: Deploys standalone OpenTelemetry Collector
  • Collects and exports traces, metrics, logs
  • When to disable: If using different observability stack (Datadog, New Relic)
# PII Detection
enable_presidio = false

What this does:

  • Deploys Microsoft Presidio for PII detection
  • Provides APIs for data anonymization
  • When to enable: Required

Core Services Configuration

ALB Ingress Controller

The ALB Ingress Controller manages AWS Application Load Balancers for your services:

enable_alb_ingress = true

# Optional: Pin to specific version
# alb_ingress_version = "1.7.1"

What gets configured automatically:

  • IAM role with permissions (from infrastructure module)
  • Service account with IRSA (IAM Roles for Service Accounts)
  • Webhook certificates
  • IngressClass named ‘alb’

How applications use it:

# In your app's Ingress resourcemetadata:  
annotations:    
  kubernetes.io/ingress.class: alb    
  alb.ingress.kubernetes.io/scheme: internet-facing    
  alb.ingress.kubernetes.io/target-type: ip

External Secrets Operator

Syncs secrets from AWS Secrets Manager to Kubernetes:

enable_external_secrets = true

# Configure secret stores
external_secrets_stores = {
  "aws-secrets-manager" = {
    provider = "aws"
    config = {
      service = "SecretsManager"
      region  = "us-west-2"  # Your AWS region
    }
  }

  # Optional: Add other secret backends
  # "vault" = {
  #   provider = "vault"
  #   config = {
  #     server = "https://vault.example.com"
  #     path   = "secret"
  #   }
  # }
}

What gets created:

  • External Secrets Operator deployment
  • ClusterSecretStore for each configured backend
  • IRSA for AWS Secrets Manager access

How applications use it:
The application Helm charts create ExternalSecret resources that reference these ClusterSecretStores.

Feature Flags Management (Unleash)

Basic Configuration

enable_unleash      = true
enable_unleash_edge = true

# Import initial feature flags (first deployment only!)
import_feature_flags = true  # Set to false after initial import
unleash_import_project = "default"
unleash_import_environment = "development"

Authentication Tokens

Default behavior

  • By default, this module consumes Unleash credentials from the kindo-secrets outputs when they are available. If an expected value is missing, a secure token/password will be generated only for that specific item. When store_secrets_in_aws is true, generated values are persisted to AWS Secrets Manager so they can be read on subsequent runs.

Example references when wiring modules explicitly:

# If you expose outputs from kindo-secrets, the peripheries module will use them
# You can pass them explicitly, or rely on composition wiring in your root module
unleash_admin_password = module.kindo_secrets.unleash_admin_password   # optional if wired implicitly
unleash_admin_token    = module.kindo_secrets.unleash_admin_token      # optional if wired implicitly
unleash_client_token   = module.kindo_secrets.unleash_client_token     # optional if wired implicitly
unleash_frontend_token = module.kindo_secrets.unleash_frontend_token   # optional if wired implicitly

Option 1: Use kindo-secrets outputs (default)

# No manual values required when kindo-secrets outputs are present.
# The module will read them automatically and skip generation for those keys.

Option 2: Auto-generate tokens

# Leave these unset — secure random tokens will be generated for any values
# not provided by kindo-secrets outputs
# unleash_admin_password =
# unleash_admin_token =
# unleash_client_token =
# unleash_frontend_token =

Option 3: Provide your own tokens

unleash_admin_password = "your-secure-admin-password"
unleash_admin_token    = "*:*.your-admin-token-here"
unleash_client_token   = "default:development.your-client-token"
unleash_frontend_token = "*:development.your-frontend-token"

Token formats explained:

  • Admin token: *:*.{token} — Full API access to all projects and environments
  • Client token: {project}:{environment}.{token} — Read-only for a specific project and environment
  • Frontend token: *:{environment}.{token} — Frontend access for all projects in an environment

Feature Flags Import

To import existing feature flags from feature_flags.json:

# WARNING: Only enable for initial deployment
import_feature_flags = true

# After successful import, update to:
# import_feature_flags = false

Important: Disable after first import to prevent re-importing on every pod restart!

Storing Unleash Tokens

# Store generated tokens in AWS Secrets Manager
store_secrets_in_aws = true

This creates secrets:

  • {project}-{environment}-unleash-tokens
  • Contains all generated Unleash authentication tokens

Secret Management (External Secrets)

AWS Secrets Manager Integration

enable_external_secrets = true

external_secrets_stores = {
  "aws-secrets-manager" = {
    provider = "aws"
    config = {
      service = "SecretsManager"
      region  = "us-west-2"
    }
  }
}

Multiple Secret Backends

You can configure multiple secret stores:

external_secrets_stores = {
  # AWS Secrets Manager
  "aws-secrets-manager" = {
    provider = "aws"
    config = {
      service = "SecretsManager"
      region  = "us-west-2"
    }
  }

  # HashiCorp Vault
  "vault" = {
    provider = "vault"
    config = {
      server = "https://vault.example.com"
      path   = "secret"
      # Auth handled via Kubernetes service account
    }
  }

  # Doppler
  "doppler" = {
    provider = "doppler"
    config = {
      auth_secret_name = "doppler-token-secret"
      # Token must be pre-created as Kubernetes secret
    }
  }
}

How Applications Use External Secrets

Applications don’t need to know about the secret backend. They create ExternalSecret resources:

# Created by app Helm charts
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:  
  name: app-secrets
  spec:  secretStore
    Ref:    
      name: aws-secrets-manager  # References ClusterSecretStore    
      kind: ClusterSecretStore  
      target:   
        name: app-secrets  
       
        # Creates this Kubernetes secret  
        data:  
        - secretKey: config    
          remoteRef:      
            key: mycompany-production-api-config

Observability Configuration

AWS Distro for OpenTelemetry (ADOT)

If using the ADOT EKS addon:

# Use Custom Resource for ADOT addon
enable_otel_collector_cr = true

# The addon must be installed on your EKS cluster
# This creates an OpenTelemetryCollector CR to configure it

What this configures:

  • Receivers: OTLP (gRPC and HTTP)
  • Processors: Batch, memory limiter
  • Exporters: AWS X-Ray (traces), CloudWatch (metrics)

Standalone OpenTelemetry Collector

If not using ADOT:

# Deploy standalone collector
enable_otel_collector = true

# Optional: Custom configuration
# otel_collector_version = "0.74.0"

What this deploys:

  • OpenTelemetry Collector as Kubernetes Deployment
  • Service for OTLP ingestion
  • ConfigMap with collector configuration

Choosing Between ADOT and Standalone

Use ADOT CR (enable_otel_collector_cr) Use Standalone (enable_otel_collector)
Running on AWS EKS Running on other Kubernetes
Want AWS-native integration Need custom exporters
Using X-Ray and CloudWatch Using Datadog, New Relic, etc.
ADOT addon already installed Want full control over config

Advanced Configuration

Custom Helm Values

Override default Helm values for any component:

# In your main.tf, when calling the module
module "kindo_peripheries" {
  source = "../../modules/kindo-peripheries"

  peripheries_config = {
    unleash = {
      install = true
      helm_chart_version = "5.4.3"
      namespace = "unleash"

      # Custom Helm values
      values_content = file("${path.module}/custom-unleash-values.yaml")

      # Dynamic value overrides
      dynamic_helm_sets = {
        "postgresql.enabled" = "false"  # Use external database
        "dbConfig.host" = "my-rds-instance.amazonaws.com"
      }

      # Sensitive value overrides
      sensitive_helm_sets = {
        "dbConfig.password" = var.unleash_db_password
      }
    }
  }
}

Custom Namespaces

Deploy components to specific namespaces:

# In peripheries_config
alb_ingress = {
  install = true
  namespace = "ingress-system"  # Custom namespace
  create_namespace = true
}

unleash = {
  install = true
  namespace = "feature-flags"   # Custom namespace
  create_namespace = true
}

Version Pinning

Pin components to specific versions:

# Component versions
alb_ingress_version      = "1.7.1"
unleash_version          = "5.4.3"
unleash_edge_version     = "3.0.0"
external_secrets_version = "0.9.9"
otel_collector_version   = "0.74.0"
presidio_version         = "2.1.95"

Domain Configuration

# Base domain for services
base_domain = "kindo.mycompany.com"

# This creates:
# - unleash.kindo.mycompany.com
# - app.kindo.mycompany.com
# - api.kindo.mycompany.com

Resource Tagging

# Additional tags for AWS resources
additional_tags = {
  Team        = "Platform"
  CostCenter  = "Engineering"
  Compliance  = "SOC2"
  Environment = "production"
}

Deployment Process

1. Pre-Deployment Checklist

  • Infrastructure deployed (kindo-infra module)
  • Secrets configured (kindo-secrets module)
  • kubectl access configured
  • terraform.tfvars completed
  • feature_flags.json present (if importing)

2. Validate Configuration

# Check cluster connectivity
kubectl get nodes
# Validate Terraform configuration
terraform fmt
terraform validate
# Preview deployment
terraform plan

3. Deploy Peripheries

# Deploy all components
terraform apply
# For CI/CD
terraform apply -auto-approve

Deployment time:

  • External Secrets Operator: 1-2 minutes
  • ALB Ingress Controller: 2-3 minutes
  • Unleash + PostgreSQL: 3-5 minutes
  • Total: 5-10 minutes

4. Save Outputs

# Save outputs for application deployment
terraform output -json > peripheries-outputs.json
# Key outputs
terraform output unleash_url
terraform output unleash_tokens  # If auto-generated

Post-Deployment Verification

1. Verify Core Services

# Check deploymentskubectl get deployments -A | grep -E "unleash|external-secrets|aws-load"# Expected output:# external-secrets   external-secrets-operator      1/1# external-secrets   external-secrets-webhook       1/1# kube-system        aws-load-balancer-controller   2/2# unleash            unleash                         1/1# unleash            unleash-edge                    1/1

2. Verify External Secrets Operator

# Check ClusterSecretStoreskubectl get clustersecretstores
# Test secret synckubectl get externalsecrets -A# Check operator logskubectl logs -n external-secrets deployment/external-secrets-operator

3. Verify ALB Ingress Controller

# Check controllerkubectl get deployment -n kube-system aws-load-balancer-controller
# Verify webhookkubectl get validatingwebhookconfiguration aws-load-balancer-webhook
# Check for IngressClasskubectl get ingressclass alb

4. Verify Unleash

# Get Unleash URLUNLEASH_URL=$(terraform output -raw unleash_url)echo "Unleash UI: https://$UNLEASH_URL"# Check Unleash podskubectl get pods -n unleash
# Get admin password (if auto-generated)kubectl get secret -n unleash unleash-admin -o jsonpath='{.data.password}' | base64 -d# Test Unleash APIcurl -H "Authorization: $(terraform output -raw unleash_admin_token)" \  https://$UNLEASH_URL/api/admin/projects

5. Verify External DNS (if enabled)

# Check External DNS deploymentkubectl get deployment -n external-dns external-dns
# Check DNS records createdaws route53 list-resource-record-sets \  --hosted-zone-id $(terraform output -raw route53_zone_id) \  --query "ResourceRecordSets[?Type=='A' || Type=='CNAME'].[Name,Type]" \  --output table

6. Verify OpenTelemetry (if enabled)

For ADOT CR:

# Check OpenTelemetryCollector resourcekubectl get opentelemetrycollectors -A# Check ADOT addonkubectl get pods -n opentelemetry-operator-system

For standalone:

# Check collector deploymentkubectl get deployment -n otel otel-collector
# Test OTLP endpointkubectl port-forward -n otel service/otel-collector 4317:4317
# In another terminal:grpcurl -plaintext localhost:4317 list

7. Create Verification Summary

cat > peripheries-summary.md << EOF# Peripheries Deployment Summary## Deployment Information- **Date**: $(date)- **Project**: $(terraform output -raw project_name)- **Environment**: $(terraform output -raw environment)- **Region**: $(terraform output -raw aws_region)## Services Deployed$(kubectl get deployments -A | grep -E "unleash|external-secrets|aws-load" | awk '{print "- " $2 " (" $1 ")"}')## Access Points- **Unleash UI**: https://$(terraform output -raw unleash_url)- **Username**: admin- **Password**: Check AWS Secrets Manager or kubectl secret## Integration Points- **ClusterSecretStores**: $(kubectl get clustersecretstores -o name | wc -l) configured- **IngressClass**: alb available- **External DNS**: $([ "$(terraform output -raw enable_external_dns)" = "true" ] && echo "Active" || echo "Not configured")## Next Steps1. Deploy applications using kindo-applications module2. Configure application ExternalSecrets3. Set up application Ingress resources4. Configure feature flags in UnleashEOFecho "✅ Summary saved to peripheries-summary.md"

Troubleshooting

Common Issues and Solutions

1. External Secrets Not Syncing

Error: “SecretSyncError: could not get secret from provider”

Solution:

# Check IRSA configurationkubectl describe sa -n external-secrets external-secrets
# Verify IAM role trust policyaws iam get-role --role-name external-secrets-role
# Check operator logskubectl logs -n external-secrets deployment/external-secrets-operator

2. ALB Not Creating

Error: “Failed to create ALB”

Solution:

# Check controller logskubectl logs -n kube-system deployment/aws-load-balancer-controller
# Verify IAM permissionskubectl describe sa -n kube-system aws-load-balancer-controller
# Check subnets have proper tagsaws ec2 describe-subnets --subnet-ids <subnet-id>

3. Unleash Connection Issues

Error: “Unable to connect to database”

Solution:

# Check PostgreSQL podkubectl get pods -n unleash | grep postgres
# Check database credentialskubectl get secret -n unleash unleash-postgresql -o yaml
# Restart Unleash podkubectl rollout restart deployment -n unleash unleash

4. Feature Flags Not Importing

Error: “Import failed”

Solution:

# Ensure import is enabled (first deployment only)
import_feature_flags = true

# Check feature_flags.json exists
ls feature_flags.json

# After successful import, disable
import_feature_flags = false

5. DNS Records Not Creating

Error: “External DNS not creating records”

Solution:

# Check External DNS logskubectl logs -n external-dns deployment/external-dns
# Verify Route53 permissionskubectl describe sa -n external-dns external-dns
# Check domain ownershipterraform output route53_zone_id

Debugging Commands

# List all peripheries resourceskubectl get all -A | grep -E "unleash|external-secrets|aws-load|otel"# Check Helm releaseshelm list -A# Verify CRDs installedkubectl get crds | grep -E "external-secrets|elbv2|opentelemetry"# Check events for issueskubectl get events -A --sort-by='.lastTimestamp' | tail -20# Enable debug loggingexport TF_LOG=DEBUG
terraform apply

Next Steps

After successful peripheries deployment:

  1. Deploy Applications: Follow the Application Deployment Guide to deploy Kindo applications
  2. Configure Ingress: Set up application routing with ALB Ingress
  3. Set Up Feature Flags: Log into Unleash and configure feature toggles
  4. Monitor Services: Check observability dashboards if configured

Appendix: Complete terraform.tfvars Reference

# ===============================================================
# Complete Peripheries Configuration Reference
# ===============================================================

# Core Configuration (REQUIRED)
project_name = "mycompany"
environment  = "production"
aws_region   = "us-west-2"

# Service Enable/Disable Flags
enable_alb_ingress      = true
enable_external_secrets = true
enable_unleash          = true
enable_unleash_edge     = true
enable_external_dns     = true
enable_otel_collector   = false
enable_otel_collector_cr = true
enable_presidio         = false

# Domain Configuration
base_domain = "kindo.mycompany.com"

# Component Versions (optional - defaults provided)
alb_ingress_version      = "1.7.1"
unleash_version          = "5.4.3"
unleash_edge_version     = "3.0.0"
external_secrets_version = "0.9.9"
otel_collector_version   = "0.74.0"
presidio_version         = "2.1.95"

# Unleash Configuration
import_feature_flags = false  # Only true for initial deployment
unleash_import_project = "default"
unleash_import_environment = "development"

# Optional: Provide your own tokens
# unleash_admin_password = "secure-password"
# unleash_admin_token = "*:*.admin-token"
# unleash_client_token = "default:development.client-token"
# unleash_frontend_token = "*:development.frontend-token"

# External Secrets Configuration
external_secrets_stores = {
  "aws-secrets-manager" = {
    provider = "aws"
    config = {
      service = "SecretsManager"
      region  = "us-west-2"
    }
  }
}

# AWS Integration
store_secrets_in_aws = true

# Resource Tagging
additional_tags = {
  Team       = "Platform"
  CostCenter = "Engineering"
  Compliance = "SOC2"
}

# Registry Configuration (only if using private charts)
# registry_username = "username"
# registry_password = "password"

Remember: Start with the minimal configuration and add parameters as needed. Most services have sensible defaults that work out of the box.