Volver a artículos
10 min de lecturaastro-ssg-aws-s3-cloudfront

Escrito por Rodrigo de Miguel

Automatizar el despliegue de un blog Astro SSG con GitHub Actions y AWS (5/5)

Cómo automatizar el despliegue de un blog Astro estático con SSG en AWS usando GitHub Actions y OIDC, quitando trabajo manual y manteniendo una CI sencilla, segura y fácil de mantener.

GitHub Actions
AWS
CI/CD
Static Site Generation SSG
Infrastructure

El último paso manual siempre acaba molestando

A estas alturas de la serie ya está todo lo importante en su sitio:

  • Un blog en Astro
  • HTML estático (SSG)
  • S3 + CloudFront sirviendo rápido y barato
  • Dominio propio y HTTPS
  • Google Search Console funcionando

Pero queda un detalle que parece menor y que, con el paso del tiempo, empieza a cansar:

👉 el despliegue sigue siendo manual.

Al principio no pasa nada.
Luego se te olvida.
Más tarde dudas: “¿esto está ya en producción?”.
Y al final, cualquier cambio pequeño se vuelve más pesado de lo que debería.

La salida es clara: automatizar el despliegue.
Eso sí, sin montar una CI exagerada para un blog.

De eso va este post.

Qué vamos a hacer (y qué no)

Sí vamos a hacer

  • Usar GitHub Actions
  • Automatizar build + deploy + invalidación de caché
  • Quitarnos de encima credenciales largas de AWS
  • Trabajar con OIDC, como se espera hoy en día

No vamos a hacer

  • Pipelines enrevesadas
  • Terraform
  • Múltiples entornos
  • Overkill “enterprise”

Esto sigue siendo un porfolio / blog personal.

GitHub Actions + AWS OIDC

Aquí hay una decisión de fondo que merece pararse un momento.

Podríamos:

  • guardar AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEY en GitHub
  • y tirar millas

Pero eso:

  • no escala bien
  • no es lo que AWS recomienda hoy
  • hemos venido a jugar

La opción sensata ahora mismo es: 👉 OIDC (OpenID Connect)

Ventajas reales:

  • No hay claves largas guardadas
  • Acceso limitado a repo + branch
  • Credenciales temporales
  • Es justo lo que AWS y GitHub recomiendan

Arquitectura final del despliegue

El flujo completo:

TEXT
git push origin main GitHub Actions Build Astro (SSG) Sync dist/ → S3 Invalidate CloudFront Web actualizada

Si el build falla: 👉 no se despliega nada

Solo con eso ya se gana mucha tranquilidad.

Paso 1 — Configurar OIDC entre GitHub y AWS

1.1 Crear Identity Provider en AWS

En AWS Console → IAM → Identity providers:

  • Provider type: OpenID Connect
  • Provider URL: https://token.actions.githubusercontent.com
  • Audience: sts.amazonaws.com

Guardar.

Con esto GitHub puede “presentarse” ante AWS de forma controlada.

1.2 Política de permisos mínima

Crea una policy de acceso al bucket y a cloudfront:

JSON
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"], "Resource": [ "arn:aws:s3:::<TU_BUCKET>", "arn:aws:s3:::<TU_BUCKET>/*" ] }, { "Effect": "Allow", "Action": "cloudfront:CreateInvalidation", "Resource": [ "arn:aws:cloudfront::<YOUR_ACCOUNT_ID>:distribution/<YOUR_DISTRIBUTION_ID>" ] } ] }

Dale un nombre bonito y guarda. Pj policy-access-s3-bucket-demo-astro-blog-s3

Con esto basta. Sin persisos abiertos.

1.3 Crear un IAM Role para GitHub Actions

En IAM → Roles → Create role:

  • Tipo: Web identity
  • Identity provider: token.actions.githubusercontent.com
  • Audience: sts.amazonaws.com
  • GitHub Organization: Tu org o usuario de GitHub
  • GitHub Repository: Tu repo
  • GitHub Branch: main (o la rama que uses)

Trust Policy (clave)

Edita la trust policy y déjala así (ajusta org/repo):

JSON
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" }, "StringLike": { "token.actions.githubusercontent.com:sub": "repo:<YOUR_GITHUB_ORG>/<YOUR_GITHUB_REPO>:ref:refs/heads/main" } } } ] }

Esto deja el acceso muy bien acotado:

  • ese repositorio
  • esa rama (main)

Guarda el ARN del role, hará falta luego.

Nada más.

Paso 2 — Variables y secrets en GitHub

En el repo → Settings → Secrets and variables → Actions

Secrets

TEXT
AWS_ROLE_ARN BLOG_DISTRIBUTION_ID

Variables (no sensibles)

TEXT
AWS_REGION BLOG_BUCKET_S3

No se guardan access keys. No hay secretos eternos rondando.

Paso 3 — Workflow de GitHub Actions

Crea el archivo:

TEXT
.github/workflows/deploy.yml

Contenido completo:

YAML
name: Deploy Astro SSG to S3 + CloudFront on: push: branches: - main workflow_dispatch: # This enables the "Run workflow" button permissions: id-token: write contents: read jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: 22 # specify the Node.js version cache: npm - name: Install dependencies run: npm ci - name: Build Astro site run: npm run build # 👇 ONLY runs if build succeeded - name: Configure AWS credentials via OIDC uses: aws-actions/configure-aws-credentials@v5.1.1 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ${{ vars.AWS_REGION }} - name: Deploy to S3 run: | aws s3 sync dist/ s3://${{ vars.BLOG_BUCKET_S3 }} \ --delete \ --region ${{ vars.AWS_REGION }} \ --cache-control max-age=31536000 - name: Invalidate CloudFront cache run: | aws cloudfront create-invalidation \ --distribution-id ${{ secrets.BLOG_DISTRIBUTION_ID }} \ --paths '/*'

Detalles importantes (experiencia real)

npm ci mejor que npm install

  • Más rápido
  • Reproducible
  • Usa exactamente el package-lock.json

Fijar versión de Node

Conviene usar la misma versión que en local.

En package.json:

JSON
"engines": { "node": "22.13.1", "npm": "10.9.2" }

Evita sorpresas raras en CI.

Listo.

Qué hemos ganado con esto

  • ✅ Cero pasos manuales
  • ✅ Deploy imposible si el build falla
  • ✅ Seguridad moderna (OIDC)
  • ✅ Infra simple y mantenible

Y lo más importante: 👉 te olvidas del despliegue

Checklist final

  • Push a main
  • GitHub Actions corre
  • Build pasa
  • S3 se sincroniza
  • CloudFront se invalida
  • Web actualizada

Si algo falla, el log no deja lugar a dudas.

Cierre de la serie

Con este post se cierra el ciclo completo:

  1. Elegir stack con cabeza
  2. Preparar Astro sin trucos raros
  3. Servir HTML con S3 + CloudFront
  4. Dominio propio y Google
  5. CI mínima y automática

No es la infraestructura más moderna. Es sencilla y cumple. Es la que menos estorba y mejor hace su trabajo.

Un saludo, devs.

Posts de la serie

1️⃣ Parte 1: Un blog no debería ser un SaaS
2️⃣ Parte 2: Preparar un blog en Astro con buen criterio
3️⃣ Parte 3: S3 + CloudFront para servir un blog estático rápido y barato
5️⃣ Parte 4: Dominio con Route 53 y CloudFront para un blog Astro SSG
👉 Parte 5: Automatizar el despliegue de un blog Astro SSG con GitHub Actions y AWS
🐙 GitHub Repo: demo-astro-ssg-s3-cloudfront

¿Hablamos?

¿Buscas a alguien que entienda el producto tanto como el código?

Abrir conversación

© 2026 Rodrigo de Miguel. Todos los derechos reservados.