> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SSL Certificate Management

> Complete guide to SSL/TLS certificate management: cert-manager vs AWS Certificate Manager (ACM)

# SSL Certificate Management

This guide covers SSL/TLS certificate management options for Runlayer, comparing cert-manager and AWS Certificate Manager (ACM) to help you choose the right approach for your deployment.

## Overview

Runlayer supports multiple certificate management approaches depending on your deployment method and requirements:

<CardGroup cols={2}>
  <Card title="cert-manager" icon="certificate">
    **Best for**: Kubernetes deployments, multi-cloud, self-managed

    Automatic Let's Encrypt certificates with full Kubernetes integration
  </Card>

  <Card title="AWS Certificate Manager" icon="aws">
    **Best for**: AWS-native deployments, enterprise environments

    Managed SSL certificates with seamless AWS service integration
  </Card>
</CardGroup>

## Comparison Matrix

| Feature                   | cert-manager          | AWS ACM                   |
| ------------------------- | --------------------- | ------------------------- |
| **Cost**                  | Free (Let's Encrypt)  | Free for AWS services     |
| **Certificate Authority** | Let's Encrypt, others | Amazon CA, imported certs |
| **Automatic Renewal**     | ✅ Every 60 days       | ✅ Automatic               |
| **Wildcard Support**      | ✅ DNS-01 challenge    | ✅ DNS validation          |
| **Multi-cloud**           | ✅ Any Kubernetes      | ❌ AWS only                |
| **Private Certificates**  | ✅ With private CA     | ✅ AWS Private CA          |
| **Setup Complexity**      | Medium                | Low                       |
| **Kubernetes Native**     | ✅ Native CRDs         | ❌ External service        |

## cert-manager Configuration

### When to Use cert-manager

* **Multi-cloud deployments** or non-AWS environments
* **Full control** over certificate lifecycle
* **Integration with private CAs** or custom issuers
* **Kubernetes-native** certificate management

### Installation and Setup

<Steps>
  <Step title="Install cert-manager">
    ```bash theme={null}
    # Add Jetstack Helm repository
    helm repo add jetstack https://charts.jetstack.io
    helm repo update

    # Install cert-manager with CRDs
    helm install cert-manager jetstack/cert-manager \
      --namespace cert-manager --create-namespace \
      --set installCRDs=true \
      --version v1.13.0
    ```
  </Step>

  <Step title="Create ClusterIssuer for Let's Encrypt">
    ```yaml theme={null}
    # letsencrypt-issuer.yaml
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        # Let's Encrypt production server
        server: https://acme-v02.api.letsencrypt.org/directory
        email: admin@yourcompany.com
        privateKeySecretRef:
          name: letsencrypt-prod
        solvers:
        # DNS-01 challenge for wildcard certificates
        - dns01:
            route53:
              region: us-east-1
              # IAM role for Route53 access (recommended with IRSA)
              role: arn:aws:iam::123456789012:role/cert-manager-route53
        # HTTP-01 challenge for single domain certificates
        - http01:
            ingress:
              class: alb  # or nginx
    ```

    ```bash theme={null}
    kubectl apply -f letsencrypt-issuer.yaml
    ```
  </Step>

  <Step title="Configure IAM for Route53 (AWS only)">
    **For DNS-01 challenges with Route53:**

    ```json theme={null}
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "route53:GetChange",
            "route53:ChangeResourceRecordSets",
            "route53:ListHostedZonesByName"
          ],
          "Resource": [
            "arn:aws:route53:::hostedzone/*",
            "arn:aws:route53:::change/*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": "route53:ListHostedZones",
          "Resource": "*"
        }
      ]
    }
    ```
  </Step>
</Steps>

### Runlayer Configuration with cert-manager

<Tabs>
  <Tab title="Single Domain">
    **Standard deployment with single domain:**

    ```yaml theme={null}
    # values-cert-manager.yaml
    ingress:
      enabled: true
      className: "alb"  # or nginx
      annotations:
        cert-manager.io/cluster-issuer: "letsencrypt-prod"
        # For ALB
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
        alb.ingress.kubernetes.io/ssl-redirect: '443'
        # For NGINX
        # nginx.ingress.kubernetes.io/ssl-redirect: "true"

      hosts:
        - host: ai.yourcompany.com
          paths:
            - path: /
              pathType: Prefix

      tls:
        - secretName: anysource-tls
          hosts:
            - ai.yourcompany.com
    ```
  </Tab>

  <Tab title="Wildcard Certificate">
    **Wildcard certificate for multiple subdomains:**

    ```yaml theme={null}
    # values-wildcard.yaml
    ingress:
      enabled: true
      className: "alb"
      annotations:
        cert-manager.io/cluster-issuer: "letsencrypt-prod"
        # Wildcard requires DNS-01 challenge
        cert-manager.io/acme-challenge-type: dns01

      hosts:
        - host: ai.yourcompany.com
          paths:
            - path: /
              pathType: Prefix
        - host: staging-ai.yourcompany.com
          paths:
            - path: /
              pathType: Prefix

      tls:
        - secretName: wildcard-tls
          hosts:
            - "*.yourcompany.com"
    ```
  </Tab>
</Tabs>

### Monitoring cert-manager

```bash theme={null}
# Check cert-manager pods
kubectl get pods -n cert-manager

# Check certificate status
kubectl get certificates -n anysource
kubectl describe certificate anysource-tls -n anysource

# Check certificate requests
kubectl get certificaterequests -n anysource

# Check cluster issuer status
kubectl describe clusterissuer letsencrypt-prod

# View cert-manager logs
kubectl logs -n cert-manager deployment/cert-manager
```

## AWS Certificate Manager (ACM)

### When to Use ACM

* **AWS-native deployments** with ALB/ELB
* **Minimal operational overhead** with managed certificates
* **Enterprise compliance** requirements
* **Integration with other AWS services**

### ACM with Application Load Balancer

<Steps>
  <Step title="Request Certificate in ACM">
    ```bash theme={null}
    # Request certificate via AWS CLI
    aws acm request-certificate \
      --domain-name ai.yourcompany.com \
      --subject-alternative-names "*.yourcompany.com" \
      --validation-method DNS \
      --region us-east-1

    # Note the certificate ARN for later use
    export CERT_ARN="arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
    ```
  </Step>

  <Step title="Validate Certificate">
    ```bash theme={null}
    # Get DNS validation records
    aws acm describe-certificate \
      --certificate-arn $CERT_ARN \
      --query 'Certificate.DomainValidationOptions'

    # Add CNAME records to your DNS provider
    # Certificate will be issued automatically once DNS records are verified
    ```
  </Step>

  <Step title="Configure ALB Ingress">
    ```yaml theme={null}
    # values-acm.yaml
    ingress:
      enabled: true
      className: "alb"
      annotations:
        kubernetes.io/ingress.class: alb
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
        # Use your ACM certificate
        alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:123456789012:certificate/your-cert-arn"
        alb.ingress.kubernetes.io/ssl-redirect: '443'
        alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01

      hosts:
        - host: ai.yourcompany.com
          paths:
            - path: /
              pathType: Prefix

      # No TLS section needed - ACM handles certificates
    ```
  </Step>
</Steps>

### ACM with Terraform (ECS Module)

The ECS Terraform module uses **wildcard certificate lookups** by default. This derives a wildcard domain from your deployment domain (e.g., `ecs.staging.runlayer.com` → `*.staging.runlayer.com`) and looks up a pre-existing certificate.

**Why wildcard certificates?** Per-domain certificates expose customer/environment names in Certificate Transparency logs (crt.sh). Wildcard certificates provide the same security while keeping deployment details private.

<Tabs>
  <Tab title="Lookup Existing (Default)">
    **Default behavior - looks up pre-existing wildcard certificate:**

    ```hcl theme={null}
    # Just specify the hosted zone - certificate lookup is automatic
    hosted_zone_name = "staging.runlayer.com"

    # The module derives: ecs.staging.runlayer.com → *.staging.runlayer.com
    # And looks up an existing ACM certificate for that wildcard domain
    ```

    Pre-created wildcard certificates for Runlayer environments:

    * `*.staging.runlayer.com` - staging AWS account
    * `*.sandbox.runlayer.com` - staging AWS account
    * `*.prod.runlayer.com` - production AWS account
  </Tab>

  <Tab title="Create New Certificate">
    **Create a new wildcard certificate with DNS validation:**

    ```hcl theme={null}
    enable_acm_dns_validation = true  # Creates new cert instead of lookup
    hosted_zone_name          = "yourcompany.com"
    ```

    This creates a wildcard certificate (e.g., `*.yourcompany.com`) and validates it via Route53.
  </Tab>

  <Tab title="Use Existing ARN">
    **Use a specific certificate ARN (bypasses module entirely):**

    ```hcl theme={null}
    ssl_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxx"
    ```
  </Tab>
</Tabs>

<Note>
  The `create_dns_records` variable (default `false`) controls whether to create the Route53 ALIAS record pointing your domain to the ALB. Set to `true` if you have a Route53 hosted zone and want Terraform to manage the DNS record. This is separate from certificate management.
</Note>

## Hybrid Approach: ACM + cert-manager

For complex deployments, you can use both:

```yaml theme={null}
# values-hybrid.yaml
ingress:
  enabled: true
  className: "alb"
  annotations:
    # Use ACM for primary production domain
    alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:us-east-1:123456789012:certificate/prod-cert"
    alb.ingress.kubernetes.io/ssl-redirect: '443'

  hosts:
    - host: ai.yourcompany.com  # ACM certificate
      paths:
        - path: /
          pathType: Prefix

# Separate ingress for development/staging with cert-manager
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: anysource-staging
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    kubernetes.io/ingress.class: nginx
spec:
  tls:
    - secretName: staging-tls
      hosts:
        - staging-ai.yourcompany.com
  rules:
    - host: staging-ai.yourcompany.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: anysource-frontend
                port:
                  number: 80
```

## Certificate Renewal

### cert-manager Renewal

```bash theme={null}
# cert-manager automatically renews certificates 30 days before expiration
# Check renewal status
kubectl get certificates -n anysource -o wide

# Force renewal (if needed)
kubectl annotate certificate anysource-tls -n anysource \
  cert-manager.io/issue-temporary-certificate="true" --overwrite

# Check renewal logs
kubectl logs -n cert-manager deployment/cert-manager -f
```

### ACM Renewal

ACM certificates are automatically renewed by AWS:

```bash theme={null}
# Check certificate status
aws acm describe-certificate --certificate-arn $CERT_ARN

# ACM automatically renews certificates 60 days before expiration
# No manual intervention required
```

## Troubleshooting

<Accordion title="cert-manager Issues">
  **Certificate stuck in pending:**

  ```bash theme={null}
  # Check certificate status
  kubectl describe certificate anysource-tls -n anysource

  # Check certificate request
  kubectl describe certificaterequest -n anysource

  # Check challenge status
  kubectl get challenges -n anysource -o wide

  # Common issues:
  # - DNS challenge failing (check Route53 permissions)
  # - HTTP challenge failing (check ingress controller)
  # - Rate limiting (Let's Encrypt limits)
  ```

  **Debugging DNS-01 challenges:**

  ```bash theme={null}
  # Check if DNS record was created
  dig _acme-challenge.ai.yourcompany.com TXT

  # Verify Route53 hosted zone
  aws route53 list-hosted-zones
  aws route53 list-resource-record-sets --hosted-zone-id Z123456789

  # Check cert-manager webhook logs
  kubectl logs -n cert-manager deployment/cert-manager-webhook
  ```
</Accordion>

<Accordion title="ACM Issues">
  **Certificate validation failing:**

  ```bash theme={null}
  # Check certificate validation status
  aws acm describe-certificate --certificate-arn $CERT_ARN \
    --query 'Certificate.DomainValidationOptions'

  # Common issues:
  # - DNS records not added to correct hosted zone
  # - DNS propagation delays (can take 24-48 hours)
  # - Domain ownership verification failing
  ```

  **ALB not using certificate:**

  ```bash theme={null}
  # Check ALB listeners
  aws elbv2 describe-listeners --load-balancer-arn $ALB_ARN

  # Verify certificate is attached
  kubectl describe ingress anysource -n anysource

  # Check ingress controller logs
  kubectl logs -n kube-system deployment/aws-load-balancer-controller
  ```
</Accordion>

## Best Practices

### Security

* **Use TLS 1.2+**: Configure modern TLS policies
* **Strong Cipher Suites**: Use secure cipher configurations
* **HSTS Headers**: Enable HTTP Strict Transport Security
* **Certificate Monitoring**: Monitor certificate expiration dates

### Operations

* **Automate DNS validation**: Use infrastructure as code for DNS records
* **Monitor certificate health**: Set up alerts for certificate issues
* **Backup certificates**: Store certificate secrets securely
* **Test certificate renewal**: Verify automatic renewal processes

### Cost Optimization

* **ACM for AWS services**: Free certificates for AWS load balancers
* **cert-manager for flexibility**: Free Let's Encrypt certificates
* **Wildcard certificates**: Reduce certificate management overhead
* **Proper certificate scoping**: Use appropriate certificate coverage

## Deployment Scenarios

<CardGroup cols={2}>
  <Card title="AWS Production" icon="aws">
    **Recommended**: ACM with ALB

    * Managed certificates
    * Automatic renewal
    * AWS integration
    * Enterprise support
  </Card>

  <Card title="Multi-cloud" icon="globe">
    **Recommended**: cert-manager

    * Platform independence
    * Kubernetes native
    * Flexible CA options
    * Full control
  </Card>

  <Card title="Development" icon="code">
    **Recommended**: cert-manager

    * Easy setup
    * Free certificates
    * Quick iteration
    * Local testing
  </Card>

  <Card title="Enterprise" icon="building">
    **Recommended**: Hybrid approach

    * ACM for production
    * cert-manager for staging
    * Private CA integration
    * Compliance requirements
  </Card>
</CardGroup>

Choose the approach that best fits your infrastructure, operational requirements, and compliance needs. Both solutions provide robust, automatic certificate management for Runlayer deployments.
