Gestionar de forma segura las credenciales de API de Sophos Central
Sophos Fusion (antes Sophos Central) puede automatizarse mediante API y conectarse a plataformas SIEM, RMM, de reporting o de seguros. Para ello no se utilizan cuentas personales de administrador, sino API Credentials propias formadas por una Client ID y un Client Secret.
Estas credenciales son identidades de máquina. Quien posea un secreto puede ejecutar todas las acciones de API permitidas por el rol de Service Principal asignado. Por eso, un secreto debe tratarse como una contraseña privilegiada y no debe almacenarse en scripts, tickets, correos electrónicos ni repositorios Git.
Diferenciar API Credentials e Integration Credential Manager
En Global Settings > Access Control hay dos áreas con nombres similares:
| Área | Función |
|---|---|
| API Credentials | Identidad técnica con la que una aplicación llama a las API de Sophos Central |
| Integration Credential Manager | Credenciales de productos externos que Sophos utiliza para integraciones como Data Ingestion o Response Actions |
Para un script propio, una consulta SIEM o un cliente de API se crean API Credentials. En cambio, las credenciales de un producto externo que deba utilizar el propio Sophos Fusion pertenecen al Integration Credential Manager.
No todas las automatizaciones requieren API Credentials generales: los usuarios y grupos se sincronizan mediante un servicio de directorio, y el software puede distribuirse con un script de instalación ejecutado localmente en cada dispositivo. Solo se crea una identidad de API para AD Sync si el proceso de sincronización previsto la requiere, y se le asigna exclusivamente el rol Service Principal Directory Sync.
Requisitos y responsabilidad
Solo un Super Admin puede crear y administrar API Credentials. La aplicación se autentica con su propia Client ID y su propio Client Secret, no con la cuenta personal del administrador.
Antes de crearla se documentan el propósito, el propietario, el sistema de destino, el rol necesario, la fecha de vencimiento y el contacto de emergencia. Se utiliza una credencial propia para cada aplicación y entorno. Un secreto compartido para el script de copia de seguridad, el SIEM y proveedores externos impide un bloqueo selectivo y dificulta el análisis de la causa.
Elegir el rol de Service Principal adecuado
Sophos ofrece varios roles:
- Service Principal Read-Only lee datos del tenant, pero no puede modificarlos ni ejecutar consultas de Live Discover.
- Service Principal Management puede consultar, crear, modificar y eliminar usuarios y grupos de usuarios; consultar y editar alertas; consultar endpoints y activar acciones como un análisis; además de ver y modificar configuraciones globales de Endpoint Protection. También administra administradores, roles y Security Policies, pero no tiene acceso a consultas de Live Discover.
- Service Principal Forensics crea, visualiza, ejecuta y elimina consultas de Live Discover.
- Service Principal Directory Sync está previsto exclusivamente para la sincronización de Active Directory y no puede ejecutar ninguna otra tarea de API.
- Service Principal Firewall limita la identidad a la administración del firewall y no permite tareas de la API de Central fuera de ella.
- Service Principal Audit Log permite que aplicaciones externas, herramientas SIEM y scripts de integración recuperen eventos del Audit Log mediante consultas de solo lectura.
- Service Principal Super Admin posee amplios permisos de lectura, escritura y eliminación, además de acceso a consultas.
La selección siempre comienza por el rol más limitado. Una integración de reporting o de ciberseguro recibe Read-Only. AD Sync recibe el rol creado específicamente para ello. Super Admin solo se utiliza si los endpoints de API documentados necesitan realmente amplios permisos de escritura y no funciona ningún rol más restringido.
Crear una credencial
Inicie sesión en fusion.sophos.com y abra Global Settings > Access Control > API Credentials. En el primer acceso deben aceptarse las condiciones de uso.
- Abrir Add Credential.
- Registrar un nombre inequívoco y una descripción con la aplicación, el entorno y el propietario.
- Seleccionar el rol de Service Principal mínimo necesario.
- Crear la credencial y copiar inmediatamente la Client ID y el Client Secret.
- Guardar el secreto en un almacén empresarial de secretos y vaciar el portapapeles temporal.
El Client Secret solo se muestra una vez. No se puede volver a visualizar más adelante. Si se pierde, no se recupera el secreto existente; se crea una credencial nueva y se elimina la antigua después de completar correctamente la migración.
Contrato de API, autenticación y región
El proceso siguiente describe las API REST de producto regionales de Sophos Central: el host Identity global emite el token OAuth; el host global whoami identifica la credencial. Para contratos REST con enrutamiento regional, las llamadas de producto del tenant usan después el host devuelto para ese tenant. Para ello, los siguientes destinos HTTPS deben ser accesibles desde la estación de administración o el sistema de integración:
POST https://id.sophos.com/api/v2/oauth2/tokenpara OAuth2;GET https://api.central.sophos.com/whoami/v1para identidad y descubrimiento del host;GET https://api.central.sophos.com/partner/v1/tenantspara credenciales de partner;GET https://api.central.sophos.com/organization/v1/tenantspara credenciales Enterprise;- el host HTTPS devuelto en
apiHosts.dataRegiono en el campo del tenantapiHostpara la API de producto.
No adivinar una URL regional ni copiarla de una tabla estática. Para este proceso REST, aceptar solo el host HTTPS completo devuelto y añadir después las rutas de producto. La validación de host del script siguiente se aplica a este contrato, no universalmente a todas las API Sophos.
La Search GraphQL API tiene su propio contrato de destino: POST JSON a https://api.taegis.sophos.com/graphql con token Bearer, X-Tenant-ID y X-GraphQL-Schema: default. No se usa el host REST regional ni se sustituye globalmente apiHosts.dataRegion. La obtención de token y la asignación al tenant siguen siendo necesarias; aclarar por separado permisos y derechos de acceso para la operación concreta. Las descripciones generales de roles anteriores no demuestran un rol mínimo Search GraphQL. El runbook de consultas Search-QL históricas detalla todo el proceso. El nombre de host por sí solo no garantiza la residencia de los datos.
Solicitar un token de acceso de forma segura
Leer el secreto sin mostrarlo y enviar los datos de formulario por la entrada estándar. Así no aparece en el historial de la shell ni como argumento expandido en la lista de procesos:
read -r -p "Client ID: " SOPHOS_CLIENT_ID
read -r -s -p "Client Secret: " SOPHOS_CLIENT_SECRET; printf '\n'
TOKEN_RESPONSE=$(printf 'grant_type=client_credentials&client_id=%s&client_secret=%s&scope=token' \
"$(printf '%s' "$SOPHOS_CLIENT_ID" | jq -sRr '@uri')" \
"$(printf '%s' "$SOPHOS_CLIENT_SECRET" | jq -sRr '@uri')" |
curl --fail-with-body --silent --show-error --request POST \
--header 'Content-Type: application/x-www-form-urlencoded' --data-binary @- \
https://id.sophos.com/api/v2/oauth2/token)
unset SOPHOS_CLIENT_SECRET
SOPHOS_ACCESS_TOKEN=$(jq -er '
select(.token_type == "bearer") |
select((.expires_in | type) == "number" and .expires_in > 0) |
.access_token | select(type == "string" and length > 0)
' <<<"$TOKEN_RESPONSE")
unset TOKEN_RESPONSE
WHOAMI=$(printf 'header = "Authorization: Bearer %s"\n' "$SOPHOS_ACCESS_TOKEN" |
curl --fail-with-body --silent --show-error --config - \
https://api.central.sophos.com/whoami/v1
)
Una respuesta correcta contiene al menos access_token, token_type: "bearer" y expires_in; también pueden aparecer refresh_token, errorCode, message y trackingId. expires_in es la duración de validez en segundos. En el flujo Client Credentials, solicitar un nuevo token al caducar en lugar de depender del refresh_token opcional. No registrar nunca la respuesta: ambos campos de token son secretos.
Evaluar whoami
Pasar la cabecera Bearer a curl por la entrada estándar y guardar solo los campos de descubrimiento no secretos. Los valores del ejemplo de respuesta de tenant son marcadores, no valores de producción.
{
"id": "<tenant-uuid>",
"idType": "tenant",
"apiHosts": {
"global": "https://api.central.sophos.com",
"dataRegion": "https://api-us03.central.sophos.com"
}
}
Con idType: "tenant", validar estrictamente UUID y host antes de usarlos. Con idType: "partner" o "organization", whoami normalmente solo contiene apiHosts.global; entonces SOPHOS_ID no es un ID de tenant. El bucle limitado utiliza la cabecera de contexto necesaria y sigue pages.total. Cada objeto tenant aporta su propio id y apiHost. Elegir el destino por un UUID de una correspondencia interna fiable, nunca solo por un nombre visible similar.
SOPHOS_ID=$(jq -er '.id | select(type == "string" and length > 0)' <<<"$WHOAMI")
SOPHOS_ID_TYPE=$(jq -er '.idType | select(. == "tenant" or . == "partner" or . == "organization")' <<<"$WHOAMI")
UUID_RE='^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$'
if [[ "$SOPHOS_ID_TYPE" == tenant ]]; then
SOPHOS_TENANT_ID=$(jq -er --arg re "$UUID_RE" '.id | select(type == "string" and test($re))' <<<"$WHOAMI")
SOPHOS_API_HOST=$(jq -er '.apiHosts.dataRegion | select(type == "string" and test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$"))' <<<"$WHOAMI")
else
case "$SOPHOS_ID_TYPE" in
partner) TENANTS_URL='https://api.central.sophos.com/partner/v1/tenants'; CONTEXT_HEADER="X-Partner-ID: ${SOPHOS_ID}" ;;
organization) TENANTS_URL='https://api.central.sophos.com/organization/v1/tenants'; CONTEXT_HEADER="X-Organization-ID: ${SOPHOS_ID}" ;;
*) exit 1 ;;
esac
TENANTS_FILE=$(mktemp); printf '[]\n' >"$TENANTS_FILE"
page=1; max_pages=1000; expected_pages=
while (( page <= max_pages )); do
PAGE_RESPONSE=$(printf 'header = "Authorization: Bearer %s"\n' "$SOPHOS_ACCESS_TOKEN" |
curl --fail-with-body --silent --show-error --get --config - \
--header "$CONTEXT_HEADER" --data-urlencode "page=${page}" \
--data-urlencode 'pageSize=100' --data-urlencode 'pageTotal=true' "$TENANTS_URL")
page_total=$(jq -er 'select((.items|type)=="array") | .pages.total | select(type=="number" and floor==. and .>=1 and .<=1000)' <<<"$PAGE_RESPONSE")
if [[ -z "$expected_pages" ]]; then expected_pages=$page_total; fi
[[ "$page_total" == "$expected_pages" ]] || exit 1
jq -e --argjson page "$PAGE_RESPONSE" '. + $page.items' "$TENANTS_FILE" >"${TENANTS_FILE}.new"
mv "${TENANTS_FILE}.new" "$TENANTS_FILE"
(( page >= expected_pages )) && break
((page++))
done
(( page == expected_pages )) || exit 1
read -r -p 'UUID del tenant de destino según la asignación aprobada: ' TARGET_TENANT_ID
TARGET_TENANT=$(jq -cer --arg id "$TARGET_TENANT_ID" --arg re "$UUID_RE" '[.[] | select((.id|type)=="string" and (.id|test($re)) and (.id|ascii_downcase)==($id|ascii_downcase)) | select((.apiHost|type)=="string" and (.apiHost|test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$")))] | select(length==1) | .[0]' "$TENANTS_FILE")
SOPHOS_TENANT_ID=$(jq -r '.id' <<<"$TARGET_TENANT")
SOPHOS_API_HOST=$(jq -r '.apiHost' <<<"$TARGET_TENANT")
rm -f "$TENANTS_FILE"
fi
export SOPHOS_TENANT_ID SOPHOS_API_HOST
Cada solicitud de producto del tenant en este proceso REST regional vincula tres valores: token Bearer, X-Tenant-ID: <Tenant-UUID> y el apiHost regional de ese tenant. No sustituir una API REST de producto regional por el host global. Un host GraphQL específico de API es independiente. scope=token no autoriza operaciones funcionales; también determinan el acceso el rol, el tenant, la licencia y el endpoint concreto.
Validación y recuperación controlada
Antes de escribir, llamar a un endpoint de lectura inocuo de la API de destino y comprobar idType esperado, UUID correcto del tenant, formato de host permitido, JSON válido, paginación completa y objetos esperados. Después confirmar con 403 un caso de prueba expresamente prohibido, sin provocar cambios en producción. Al terminar la sesión, eliminar token de acceso, ID del tenant y host:
unset SOPHOS_ACCESS_TOKEN SOPHOS_CLIENT_ID SOPHOS_ID SOPHOS_ID_TYPE
unset SOPHOS_TENANT_ID SOPHOS_API_HOST WHOAMI
Si el tenant o el host son incorrectos, detener inmediatamente la ejecución, no enviar escrituras y aislar los resultados guardados como datos potencialmente ajenos al tenant, o eliminarlos según las normas. Revertir un cambio funcional ya realizado mediante el rollback de producto documentado previamente; eliminar la credencial solo revoca llamadas futuras y no deshace cambios.
Resolver problemas del acceso común a la API
400: comprobar codificación del formulario, campos obligatorios y exactamentegrant_type=client_credentialsyscope=token.401: comprobar existencia y caducidad de la credencial, último conjunto de secretos, token y sintaxis Bearer; después autenticar de nuevo una vez.403: la identidad está autenticada, pero falta rol, acceso al tenant o permiso específico de operación. No asignar Super Admin de forma general.404: comprobar host global o regional, versión API y ruta; no buscar la región por tanteo.429: respetarRetry-Aftery reintentar de forma limitada con backoff y jitter.5xx: guardar ID de solicitud otrackingId, hora, método y ruta con los datos sensibles ocultados y reintentar dentro de un límite; no copiar secretos ni tokens en tickets de soporte.idTypeinesperado o falta deapiHost: no construir cabeceras de tenant. Comprobar tipo de credencial y lista de tenants Partner/Enterprise completamente paginada.
Probar la autenticación de forma controlada
La primera prueba no es una escritura en producción. Para la prueba REST regional mostrada aquí, obtener primero un token de acceso OAuth del endpoint Sophos Identity. Después, whoami proporciona identidad, tipo de cuenta y, para credenciales de tenant, host API regional; las credenciales de partner y organización requieren la lista de tenants. Solo entonces realizar una lectura inocua contra el host API REST devuelto para ese tenant.
No copiar un host API REST regional de un ejemplo. Para este contrato, usar la URL proporcionada por whoami o la lista de tenants; Search GraphQL usa el host independiente descrito arriba. El ID del tenant y el ID de la organización tampoco son intercambiables.
Para la prueba se documentan, como mínimo, estos casos:
- La autenticación con la nueva identidad funciona.
- Se devuelve el tenant esperado.
- Las operaciones de lectura permitidas funcionan.
- Una operación no permitida se rechaza con
403 Forbidden. - El sistema de destino registra la prueba de forma trazable sin guardar el Client Secret.
Gestionar el vencimiento y la rotación
Sophos no envía ninguna advertencia cuando caduca una API Credential. Tras el vencimiento ya no puede utilizarse para autenticarse y Sophos Fusion la elimina automáticamente. Por tanto, la supervisión debe realizarse fuera de Sophos Fusion.
Un procedimiento de rotación correcto utiliza un solapamiento breve:
- Crear una nueva credencial con un rol idéntico o más restringido.
- Cambiar la aplicación a la Client ID y el secreto de la nueva credencial.
- Probar la autenticación y la función técnica.
- Eliminar la credencial antigua.
- Revisar el cambio en el registro de secretos y la documentación operativa.
La credencial antigua no permanece activa durante meses por precaución. Si una aplicación solo admite un juego de secretos, se planifica una ventana de mantenimiento.
Sustituir los antiguos tokens de la API SIEM
API Token Management es el método de autenticación anterior para la SIEM Integration API. Sophos ya no emite allí tokens nuevos ni prolonga la vigencia de los existentes. Los tokens actuales solo funcionan hasta su vencimiento.
Por eso no se deja hasta el último día una integración que todavía los utilice. Se registran en un inventario el token, el sistema de destino, la fecha de vencimiento y los endpoints utilizados; se crea una API Credential adecuada, se migra la aplicación y se comprueba el flujo de datos completo. El token antiguo solo se elimina después de una comprobación paralela satisfactoria.
El cambio de un token heredado a API Credentials no es un simple cambio de nombre. La integración debe ser compatible con la autenticación OAuth, whoami, el host regional y el modelo de roles. Por eso, un conector SIEM se configura conforme a las instrucciones actuales de su fabricante, no con un ejemplo antiguo basado en tokens.
Proveedores externos y acceso de terceros
Para una entidad externa se crea una identidad Service Principal Read-Only propia si bastan permisos de lectura. La Client ID y el secreto se transmiten por un canal independiente y cifrado. Se fija una fecha de finalización para el acceso y se elimina al terminar el proyecto.
Este acceso de terceros puede leer mediante la API, en particular, Alerts and Events, resultados del Account Health Check, detalles de dispositivos y configuraciones de políticas. Read-Only impide añadir, modificar y eliminar contenido en Sophos Fusion, pero no limita automáticamente qué datos legibles consulta o almacena realmente la plataforma externa. Por eso, antes de habilitar el acceso se acuerdan contractualmente el alcance de los datos, su finalidad, el lugar de almacenamiento, la retención y la eliminación.
La creación sigue la ruta habitual Global Settings > Access Control > API Credentials > Add Credential. En el primer acceso se aceptan las condiciones de uso y protección de datos, se elige Service Principal Read-Only como rol y se copian de inmediato y de forma segura la Client ID y el Client Secret, que solo se muestra una vez. La transmisión se realiza por un canal cifrado autorizado, por ejemplo, el portal HTTPS del proveedor, no por correo electrónico ni en el texto de un ticket.
El host de API no se copia de una tabla regional estática. La aplicación determina mediante whoami el host de API válido para ese tenant concreto. De este modo, la integración sigue correctamente documentada aunque Sophos cambie regiones o endpoints. En cuanto el proveedor externo deje de necesitar acceso, se elimina la credencial; así se revoca de inmediato el permiso de API.
No es aceptable exportar la cuenta personal de Super Admin, utilizar una identidad de API compartida para varios clientes ni incluir un secreto en un ticket de soporte. El proveedor también debe indicar dónde se almacena el secreto, cómo se protege y cuándo se elimina.
Delimitar los errores de forma específica
401 Unauthorized
Por lo general, la Client ID, el secreto, el endpoint de token o la solicitud OAuth son incorrectos. Una credencial caducada y ya eliminada también produce este error. Primero se comprueba si la credencial sigue existiendo en Sophos Fusion y si la aplicación utiliza realmente el juego de secretos más reciente.
403 Forbidden
La autenticación se ha realizado correctamente, pero el rol no permite la acción. En lugar de asignar inmediatamente Super Admin, se relaciona el endpoint de API necesario con el rol de Service Principal apropiado.
Token correcto, región de datos incorrecta
El token de acceso por sí solo no determina el host API de producto. Para una API REST de producto con enrutamiento regional, la aplicación debe usar el host regional proporcionado por whoami o la lista de tenants; Search GraphQL tiene su propio contrato de destino. Un host fijo de otra región provoca errores o consultas contra el límite de plataforma equivocado.
La integración falla sin advertencia
Si Sophos Fusion no muestra ninguna alerta abierta, se comprueban en el sistema de destino la fecha de vencimiento, la última llamada de API correcta y la versión del secreto. La supervisión del vencimiento forma parte del monitoring externo.
Revisión periódica
Al menos cada trimestre se revisan el nombre, el propietario, el rol, el último uso, el vencimiento y el sistema de destino de cada credencial. Las identidades que no puedan asignarse o no se utilicen se eliminan. Si se sospecha que un secreto se ha filtrado, la credencial afectada se elimina inmediatamente y se sustituye por una nueva. Después se examinan los registros del sistema de destino y de la integración en busca de llamadas de API inusuales.
Los permisos personales de administrador se revisan por separado conforme a Asignar correctamente los roles de administración de Sophos Fusion. Las API Credentials no sustituyen ni MFA ni un acceso de administrador personal y trazable.