Importar entradas dns en route53 para generarlas con terraform

Los que trabajamos con AWS hemos observado que no existe ninguna manera de hacer una copia de seguridad de las entradas dns de un dominio en route53.

Con lo que he hecho un pequeño script que importa en un fichero json las entradas dns y a la vez crea una plantilla en terraform para poder crearlas en caso de perder alguna.

Solo hay que configurar las variables de la zona hosteada, el dominio, la región de aws y la cuenta y asegurarse de tener instaladas las librerias de awscli y jq.

El script es el siguiente:

#!/bin/bash

# Define el ID de la zona alojada
HOSTED_ZONE_ID="<hosted_zone_id>"
ZONE_NAME="example.com"
AWS_REGION="<aws_region>"
AWS_ACCOUNT_ID="aws_account_id>"

# Archivo de salida
OUTPUT_FILE="route53.tf"
JSON_OUTPUT_FILE="route53.json"

# Crear o limpiar el archivo de salida JSON
echo "# Exportando registros DNS de Route53 a JSON" > $JSON_OUTPUT_FILE

# Listar todos los registros DNS en la zona y guardar en JSON
aws route53 list-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --output json > $JSON_OUTPUT_FILE

# Crear o limpiar el archivo de salida de Terraform
echo "# Route53 DNS records" > $OUTPUT_FILE

# Añadir el provider de AWS al inicio del archivo Terraform
cat <<EOL >> $OUTPUT_FILE
provider "aws" {
  region              = $AWS_REGION
  allowed_account_ids = [$AWS_ACCOUNT_ID]
}

EOL

# Procesar el archivo JSON para generar el código Terraform
jq -c '.ResourceRecordSets[]' $JSON_OUTPUT_FILE | while read record; do
  # Verificar si el registro tiene comillas dobles y crear una variable de control "quotes"
  if [[ "$record" == *"\"\""* ]]; then
    quotes="true"
    # Quitar comillas dobles escapadas para el procesamiento
    record=$(echo $record | sed 's/""/"/g')
  else
    quotes="false"
  fi

  # Procesar el registro con jq
  NAME=$(echo $record | jq -r '.Name')
  TYPE=$(echo $record | jq -r '.Type')
  TTL=$(echo $record | jq -r '.TTL')

  # Limpiar el nombre del recurso para que sea un nombre válido en Terraform
  RESOURCE_NAME=$(echo "$NAME" | tr -cd '[:alnum:]_-')_${TYPE}

  # Verificar si es un alias o un registro con ResourceRecords
  IS_ALIAS=$(echo $record | jq -r 'has("AliasTarget")')

  if [[ "$IS_ALIAS" == "true" ]]; then
    # Es un registro alias
    ALIAS_DNS=$(echo $record | jq -r '.AliasTarget.DNSName')
    ALIAS_ZONE_ID=$(echo $record | jq -r '.AliasTarget.HostedZoneId')
    EVALUATE_HEALTH=$(echo $record | jq -r '.AliasTarget.EvaluateTargetHealth')

    # Añadir la plantilla de alias al archivo de salida
    cat <<EOL >> $OUTPUT_FILE
resource "aws_route53_record" "${RESOURCE_NAME}" {
  zone_id = "$HOSTED_ZONE_ID"
  name    = "$NAME"
  type    = "$TYPE"
  alias {
    name                   = "$ALIAS_DNS"
    zone_id                = "$ALIAS_ZONE_ID"
    evaluate_target_health = $EVALUATE_HEALTH
  }
}

EOL

  else
    # Procesar los registros no alias
    VALUES=$(echo $record | jq -r '.ResourceRecords[].Value')

    # Si es un registro de tipo A o CNAME (IP o dominio), rodearlo con comillas dobles
    if [[ "$TYPE" == "A" || "$TYPE" == "CNAME" || "$TYPE" == "NS" || "$TYPE" == "SOA" ]]; then
      VALUES=$(echo $VALUES | sed 's/[^"]\+/"&"/g')
    fi

    # Si tenía comillas dobles originalmente, volver a agregarlas
    if [[ "$quotes" == "true" ]]; then
      VALUES="\"\\\"$VALUES\\\"\""
    fi

    # Añadir la plantilla de registro normal al archivo de salida
    cat <<EOL >> $OUTPUT_FILE
resource "aws_route53_record" "${RESOURCE_NAME}" {
  zone_id = "$HOSTED_ZONE_ID"
  name    = "$NAME"
  type    = "$TYPE"
  ttl     = $TTL
  records = [$VALUES]
}

EOL

  fi

  echo "Registro DNS añadido a route53.tf: $NAME ($TYPE)"
done