Azure CLI es la herramienta oficial de Microsoft para gestionar recursos de Azure desde la terminal con el comando az: suscripciones, grupos de recursos, máquinas virtuales, almacenamiento y el resto de servicios. En este tutorial instalarás Azure CLI en Ubuntu 24.04 desde el repositorio oficial de Microsoft, iniciarás sesión desde un servidor sin navegador, organizarás recursos en un grupo, subirás archivos a Blob Storage y crearás un service principal con permisos limitados para ejecutar tareas automáticas.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con arquitectura x86_64 o arm64.
  • Un usuario no root con privilegios sudo.
  • Una cuenta de Microsoft Azure con una suscripción activa y el rol Propietario (Owner) sobre ella o sobre un grupo de recursos, necesario para asignar roles en el paso 7.

Paso 1: Añadir el repositorio de Microsoft

Instalar desde el repositorio de Microsoft permite actualizar Azure CLI con apt. Instala las dependencias necesarias:

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

Descarga la clave de firma de Microsoft y guárdala en /etc/apt/keyrings:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/keyrings/microsoft.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/microsoft.gpg

Crea el archivo del repositorio en formato deb822. El nombre en clave de la versión (noble en Ubuntu 24.04) y la arquitectura se obtienen automáticamente:

echo "Types: deb
URIs: https://packages.microsoft.com/repos/azure-cli/
Suites: $(lsb_release -cs)
Components: main
Architectures: $(dpkg --print-architecture)
Signed-by: /etc/apt/keyrings/microsoft.gpg" | sudo tee /etc/apt/sources.list.d/azure-cli.sources

Paso 2: Instalar Azure CLI

Actualiza el índice de paquetes e instala azure-cli:

sudo apt update
sudo apt install -y azure-cli

Comprueba que el comando funciona:

az version
{
  "azure-cli": "2.xx.x",
  "azure-cli-core": "2.xx.x",
  "azure-cli-telemetry": "1.1.0",
  "extensions": {}
}

Paso 3: Iniciar sesión sin navegador

az login intenta abrir un navegador, algo que no existe en un servidor remoto. Usa el flujo de código de dispositivo:

az login --use-device-code

El comando muestra un mensaje como este:

To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ABCD1234 to authenticate.

Abre esa página en el navegador de tu ordenador, introduce el código e inicia sesión con tu cuenta de Azure. Al terminar, la terminal muestra las suscripciones a las que tienes acceso y, si hay más de una, te pide que elijas la que se usará por defecto.

Los tokens se guardan en ~/.azure del usuario actual y se renuevan solos, así que no tendrás que repetir el inicio de sesión en cada comando.

Paso 4: Seleccionar la suscripción activa

Cada comando de az actúa sobre una suscripción. Lista las disponibles:

az account list --output table
Name                  CloudName    SubscriptionId                        TenantId                              State    IsDefault
--------------------  -----------  ------------------------------------  ------------------------------------  -------  -----------
Producción            AzureCloud   11111111-1111-1111-1111-111111111111  aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa  Enabled  True
Pruebas               AzureCloud   22222222-2222-2222-2222-222222222222  aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa  Enabled  False

Cambia la suscripción activa por nombre o por ID:

az account set --subscription "Pruebas"

Comprueba cuál está activa. --query filtra la respuesta con sintaxis JMESPath y --output elige el formato de la respuesta:

az account show --query "{nombre:name, id:id}" --output table

Paso 5: Configurar valores por defecto

Por defecto az responde en JSON. Si prefieres tablas para el trabajo interactivo, cambia el formato de salida global:

az config set core.output=table

También puedes fijar un grupo de recursos y una región por defecto para no repetirlos en cada comando. Hazlo después de crear el grupo en el paso siguiente:

az configure --defaults group=mi-grupo location=westeurope

Estos ajustes se guardan en ~/.azure/config. Consulta los valores por defecto activos con az configure --list-defaults.

Paso 6: Crear un grupo de recursos y una cuenta de almacenamiento

Un grupo de recursos es un contenedor lógico: todo lo que creas en Azure pertenece a uno, y borrar el grupo borra todo su contenido. Crea uno en la región de Europa Occidental:

az group create --name mi-grupo --location westeurope

Crea una cuenta de almacenamiento dentro del grupo. Su nombre es global en Azure, debe tener entre 3 y 24 caracteres y solo puede contener minúsculas y números:

az storage account create \
  --name tualmacenamiento \
  --resource-group mi-grupo \
  --location westeurope \
  --sku Standard_LRS \
  --min-tls-version TLS1_2 \
  --allow-blob-public-access false

Crea un contenedor de blobs para las copias de seguridad. --auth-mode login usa tu identidad de Azure en lugar de las claves de la cuenta de almacenamiento, pero requiere un rol de datos. Asígnate el rol Storage Blob Data Contributor sobre la cuenta:

az role assignment create \
  --assignee "$(az ad signed-in-user show --query id --output tsv)" \
  --role "Storage Blob Data Contributor" \
  --scope "$(az storage account show --name tualmacenamiento --resource-group mi-grupo --query id --output tsv)"

La asignación puede tardar uno o dos minutos en aplicarse. Después, crea el contenedor y sube un archivo de prueba:

az storage container create --account-name tualmacenamiento --name backups --auth-mode login
echo "prueba" > /tmp/prueba.txt
az storage blob upload --account-name tualmacenamiento --container-name backups \
  --name prueba.txt --file /tmp/prueba.txt --auth-mode login

Lista el contenido del contenedor para verificar la subida:

az storage blob list --account-name tualmacenamiento --container-name backups \
  --auth-mode login --query "[].{nombre:name, bytes:properties.contentLength}" --output table
Nombre      Bytes
----------  -------
prueba.txt  7

Paso 7: Crear un service principal para automatizar tareas

Para scripts que se ejecutan sin intervención, como una copia nocturna, no uses tu cuenta personal. Crea un service principal, una identidad de aplicación, y dale solo el rol que necesita sobre la cuenta de almacenamiento:

SCOPE=$(az storage account show --name tualmacenamiento --resource-group mi-grupo --query id --output tsv)
az ad sp create-for-rbac --name sp-backup-servidor --role "Storage Blob Data Contributor" --scopes "$SCOPE"

La salida contiene las credenciales:

{
  "appId": "33333333-3333-3333-3333-333333333333",
  "displayName": "sp-backup-servidor",
  "password": "xxxx~xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "tenant": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
}

En el servidor, crea un usuario de sistema para las copias y guarda el secreto en un archivo que solo él pueda leer. Sustituye el valor por el password real:

sudo useradd --system --create-home --home-dir /var/lib/azbackup --shell /usr/sbin/nologin azbackup
sudo install -d -m 700 -o azbackup -g azbackup /var/lib/azbackup/.secrets
sudo -u azbackup sh -c 'umask 077; cat > /var/lib/azbackup/.secrets/sp-secret' <<'EOF'
xxxx~xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF

Inicia sesión como el service principal con ese usuario. Sustituye APP_ID y TENANT_ID por los valores de la salida anterior. --allow-no-subscriptions evita un error si el service principal no tiene roles a nivel de suscripción, como en este caso:

sudo -u azbackup -H sh -c 'az login --service-principal -u APP_ID -p "$(cat /var/lib/azbackup/.secrets/sp-secret)" --tenant TENANT_ID --allow-no-subscriptions --output none'

Comprueba que la sesión queda guardada y que el service principal puede escribir en el contenedor:

sudo -u azbackup -H az storage blob upload --account-name tualmacenamiento --container-name backups \
  --name prueba-sp.txt --file /tmp/prueba.txt --auth-mode login --overwrite --output none
sudo -u azbackup -H az storage blob list --account-name tualmacenamiento --container-name backups \
  --auth-mode login --query "[].name" --output tsv
prueba-sp.txt
prueba.txt

La sesión del service principal se guarda en /var/lib/azbackup/.azure y la CLI renueva el token automáticamente, así que los scripts que ejecute este usuario pueden llamar a az sin volver a iniciar sesión.

Paso 8: Programar una copia de seguridad diaria

Con el service principal configurado, un script corto basta para empaquetar un directorio y subirlo. Crea el script:

sudo nano /usr/local/bin/backup-azure.sh
#!/usr/bin/env bash
set -euo pipefail

ORIGEN="/var/www"
CUENTA="tualmacenamiento"
CONTENEDOR="backups"
ARCHIVO="www-$(hostname -s)-$(date +%F).tar.gz"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

tar -czf "$TMP/$ARCHIVO" -C "$(dirname "$ORIGEN")" "$(basename "$ORIGEN")"

az storage blob upload \
  --account-name "$CUENTA" \
  --container-name "$CONTENEDOR" \
  --name "$ARCHIVO" \
  --file "$TMP/$ARCHIVO" \
  --auth-mode login \
  --overwrite \
  --output none

echo "Subido $ARCHIVO"

Hazlo ejecutable y pruébalo con el usuario azbackup, que necesita permiso de lectura sobre el directorio de origen:

sudo chmod 755 /usr/local/bin/backup-azure.sh
sudo -u azbackup -H /usr/local/bin/backup-azure.sh
Subido www-mi-servidor-2026-09-25.tar.gz

Programa su ejecución diaria a las 3:30 con un temporizador de systemd. Crea el servicio:

sudo nano /etc/systemd/system/backup-azure.service
[Unit]
Description=Copia de /var/www a Azure Blob Storage
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=azbackup
Environment=HOME=/var/lib/azbackup
ExecStart=/usr/local/bin/backup-azure.sh

Y el temporizador:

sudo nano /etc/systemd/system/backup-azure.timer
[Unit]
Description=Copia diaria a Azure Blob Storage

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true

[Install]
WantedBy=timers.target

Activa el temporizador y comprueba la próxima ejecución:

sudo systemctl daemon-reload
sudo systemctl enable --now backup-azure.timer
systemctl list-timers backup-azure.timer

Para lanzarlo manualmente y ver el resultado, ejecuta sudo systemctl start backup-azure.service y después journalctl -u backup-azure.service -n 20.

Paso 9: Actualizar Azure CLI

Como la instalación viene del repositorio de Microsoft, Azure CLI se actualiza con el resto del sistema:

sudo apt update
sudo apt install --only-upgrade azure-cli

Solución de problemas

Please run 'az login' to setup account. El usuario que ejecuta el comando no tiene sesión iniciada. Recuerda que cada usuario del sistema tiene su propio ~/.azure: inicia sesión con el mismo usuario que ejecutará los comandos, por ejemplo azbackup.

AuthorizationPermissionMismatch o This request is not authorized to perform this operation al usar blobs. Con --auth-mode login hace falta un rol de datos, como Storage Blob Data Contributor; los roles Propietario o Colaborador no dan acceso a los datos por sí solos. Comprueba las asignaciones con az role assignment list --scope "$SCOPE" --output table y espera un par de minutos tras crear una.

AADSTS7000215: Invalid client secret provided. El secreto del service principal es incorrecto o ha caducado. Genera uno nuevo con az ad sp credential reset --id APP_ID, actualiza el archivo de secreto e inicia sesión de nuevo.

The subscription ... could not be found. La suscripción activa no es la que esperas. Revisa la lista con az account list --output table y cámbiala con az account set.

Conclusión

Has instalado Azure CLI en Ubuntu 24.04 desde el repositorio de Microsoft, has iniciado sesión con código de dispositivo, has creado un grupo de recursos y una cuenta de almacenamiento, y has automatizado una copia diaria con un service principal limitado a esa cuenta. Como siguientes pasos puedes añadir una política de administración del ciclo de vida a la cuenta de almacenamiento para borrar copias antiguas, crear máquinas virtuales con az vm create, o describir tus recursos con plantillas Bicep y desplegarlas con az deployment group create.