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.
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_IDyAWS_SECRET_ACCESS_KEYen 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:
git push origin main
↓
GitHub Actions
↓
Build Astro (SSG)
↓
Sync dist/ → S3
↓
Invalidate CloudFront
↓
Web actualizadaSi 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:
{
"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):
{
"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
AWS_ROLE_ARN
BLOG_DISTRIBUTION_IDVariables (no sensibles)
AWS_REGION
BLOG_BUCKET_S3No se guardan access keys. No hay secretos eternos rondando.
Paso 3 — Workflow de GitHub Actions
Crea el archivo:
.github/workflows/deploy.ymlContenido completo:
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:
"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:
- Elegir stack con cabeza
- Preparar Astro sin trucos raros
- Servir HTML con S3 + CloudFront
- Dominio propio y Google
- 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↗