Control de acceso en la API de SQL de Azure Cosmos DB

Azure Cosmos DB es un servicio de bases de datos NoSQL totalmente administrado para el desarrollo de aplicaciones modernas. En este artículo se describe SQL API de Azure Cosmos DB. El acceso a los recursos de SQL API se rige por un token de clave maestra o un token de recurso. Para tener acceso a un recurso, el token seleccionado se incluye en el encabezado de autorización de REST, como parte de la cadena de autorización.

Tokens de clave maestra

El token de clave maestra es el token de clave de acceso que permite a los usuarios tener control total de los recursos de Cosmos DB en una cuenta determinada. La clave maestra se crea durante la creación de una cuenta. Hay dos conjuntos de claves maestras, la clave principal y la clave secundaria. El administrador de cuenta puede ejercer la rotación de claves con la clave secundaria. Además, el administrador de cuenta puede regenerar las claves según sea necesario. Para obtener instrucciones sobre cómo regenerar y revertir claves, consulte Protección del acceso a los datos en Azure Cosmos DB.

Tokens de recursos

Los tokens de recursos se crean cuando los usuarios de una base de datos están configurados con permisos de acceso para un control de acceso preciso en un recurso, también conocido como recurso de permiso. Un recurso de permiso contiene un token de recurso hash construido con la información relacionada con la ruta de acceso del recurso y el tipo de acceso al que un usuario tiene acceso. El token de recurso de permiso está limitado en el tiempo y el período de validez se puede reemplazar. Cuando se actúa (POST, GET, PUT) sobre un recurso de permiso, se genera un nuevo token de recurso. Para obtener información sobre los permisos y los tokens de recursos, consulte Operaciones en permisos de Cosmos DB.

Encabezado de autorización

Todas las operaciones REST, tanto si usa un token de clave maestra como un token de recurso, deben incluir el encabezado de autorización con la cadena de autorización para interactuar con un recurso. La cadena de autorización tiene el formato siguiente:

type={typeoftoken}&ver={tokenversion}&sig={hashsignature}  

Una cadena de autorización tiene este aspecto:

type=master&ver=1.0&sig=5mDuQBYA0kb70WDJoTUzSBMTG3owkC0/cEN4fqa18/s=  

Los elementos entre llaves son los siguientes:

  • {typeoftoken} indica el tipo de token: maestro, recurso o aad(si usa RBAC de Azure Cosmos DB).

  • {tokenversion} indica la versión del token, actualmente 1.0.

  • {hashsignature} indica la firma de token con hash o el token de oauth si usa RBAC de Azure Cosmos DB.

Se debe codificar la cadena de autorización antes de agregarla a la solicitud REST, para comprobar que no contiene ningún carácter no válido. Asegúrese de que está codificado en Base64 mediante MIME RFC2045. Además, la clave maestra usada en la firma hash debe descodificarse mediante MIME RFC2045, ya que está codificada en Base64. Si ve algún problema con la autorización, consulte cómo diagnosticar y solucionar problemas de excepciones no autorizadas.

Construcción de la firma de token con hash para un token maestro

La firma hash del token de clave maestra se puede construir a partir de los parámetros siguientes: Verb, ResourceType, ResourceLink y Date.

  1. El verbo representa el verbo HTTP de la solicitud. Los valores posibles son: get, post, put, patch, delete

Nota: Los valores deben estar en minúsculas.

  1. La parte ResourceType de la cadena identifica el tipo de recurso para el que está la solicitud. Los valores posibles son:
    • Operaciones de base de datos: dbs
    • Operaciones de contenedor: colls
    • Procedimientos almacenados: sprocs
    • Funciones definidas por el usuario: udfs
    • Desencadenantes: triggers
    • Usuarios: users
    • Permisos: permissions
    • Operaciones de nivel de elemento: docs

Nota: Los valores distinguen mayúsculas de minúsculas y deben estar en minúsculas.

  1. La parte ResourceLink de la cadena es la propiedad identity del recurso al que se dirige la solicitud. El valor de ResourceLink depende de la operación que está intentando ejecutar. Cada operación tendrá su propio ResourceLink correspondiente siguiendo esta convención:
    • Si la operación se realiza en un recurso específico, el valor es el vínculo a ese recurso. Ejemplos:

      • Para Obtener base de datos, use: dbs/{databaseId}
      • Para Obtener uso del documento: dbs/{databaseId}/colls/{containerId}/docs/{docId}
    • Si la operación se realiza en un conjunto de recursos (Lista, Crear, Consulta), el valor es el vínculo del recurso primario. Ejemplos:

      • Para Crear uso de documento: dbs/{databaseId}/colls/{containerId}
      • Para Crear procedimiento almacenado, use: dbs/{databaseId}/colls/{containerId}
      • Para Crear un contenedor, use: dbs/{databaseId}
      • Para Crear base de datos use: "" :> una cadena vacía, ya que las bases de datos no tienen un recurso primario

Nota: Los nombres de recursos a los que se hace referencia como parte del valor resourceLink distinguen mayúsculas de minúsculas y deben coincidir con las mayúsculas y minúsculas de cómo se declararon en la base de datos. Los demás componentes deben estar en minúsculas.

  1. La parte Fecha de la cadena es la fecha UTC y la hora en que se envió el mensaje (en formato "FECHA HTTP", tal y como se define en formatos de fecha y hora RFC 7231), por ejemplo, "Tue, 01 nov 1994 08:12:31 GMT".

    En C#, se puede obtener mediante el especificador de formato "R" en el DateTime.UtcNow valor.

    Esta misma fecha (en el mismo formato) también debe pasarse como x-ms-date encabezado en la solicitud.

Nota: El valor distingue mayúsculas de minúsculas y debe estar en minúsculas.

Para calcular la firma, usamos la función de código de autenticación de mensajes basado en hash (HMAC) basada en SHA256 con la clave de CosmosDB como secreto.

La carga de la función hash se basa en los 4 componentes presentados anteriormente con el siguiente formato: "{verb}\n{resourceType}\n{resourceLink}\n{date}\n\n" (tenga en cuenta la nueva línea adicional al final de la carga).

El resultado codificado en Base64 de la función se usará como firma al construir el encabezado Authorization para la llamada.

Ejemplo [C#] para un encabezado de autorización válido:

    httpClient.DefaultRequestHeaders.Clear();
    httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
    httpClient.DefaultRequestHeaders.Add("authorization", auth); //generated using method below
    httpClient.DefaultRequestHeaders.Add("x-ms-date", requestDateString);
    httpClient.DefaultRequestHeaders.Add("x-ms-version", "2018-12-31");

Ejemplo [C#] método para generar una firma de autorización válida:

Para ver ejemplos completos de la API REST de Cosmos DB, visite el repositorio de ejemplos de la API REST de Cosmos DB en GitHub.

  
string GenerateMasterKeyAuthorizationSignature(HttpMethod verb, ResourceType resourceType, string resourceLink, string date, string key)
{
    var keyType = "master";
    var tokenVersion = "1.0";
    var payload = $"{verb.ToString().ToLowerInvariant()}\n{resourceType.ToString().ToLowerInvariant()}\n{resourceLink}\n{date.ToLowerInvariant()}\n\n";

    var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
    var hashPayload = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payload));
    var signature = Convert.ToBase64String(hashPayload);
    var authSet = WebUtility.UrlEncode($"type={keyType}&ver={tokenVersion}&sig={signature}");

    return authSet;
}
  

Ejemplo [Node.js]:

  
var crypto = require("crypto");  
  
function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceId, date, masterKey) {  
    var key = new Buffer(masterKey, "base64");  
  
    var text = (verb || "").toLowerCase() + "\n" +   
               (resourceType || "").toLowerCase() + "\n" +   
               (resourceId || "") + "\n" +   
               date.toLowerCase() + "\n" +   
               "" + "\n";  
  
    var body = new Buffer(text, "utf8");  
    var signature = crypto.createHmac("sha256", key).update(body).digest("base64");  
  
    var MasterToken = "master";  
  
    var TokenVersion = "1.0";  
  
    return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);  
}  
  

Codificación de ejemplo:

Argumento Value
Verbo GET
Tipo de recurso "dbs"
Vínculo de recursos "dbs/ToDoList"
Fecha Thu, 27 abr 2017 00:51:12 GMT
Clave dsZQi3KtZmCv1ljt3VNWNm7sQUF1y5rJfC6kv5Jiwv
W0EndXdDku/dkKBp8/ufDToSxLzR4y+O/0H/t4bQtVNw==
Tipo de clave maestro
Versión del token 1.0
Cadena de autorización de salida type%3dmaster%26ver%3d1.0%26sig%3dc09PEVJr
gp2uQRkr934kFbTqhByc7TVr3OHyqlu%2bc%2bc%2bc%3d

Construcción de la firma hash para un token de recurso

Un servidor intermedio debe generar tokens de recursos. El servidor actúa como guardián de clave maestra y genera tokens restringidos por tiempo para clientes que no son de confianza, como exploradores web.

Este servidor realiza los pasos siguientes:

  1. Controla las solicitudes de cliente entrantes para los nuevos tokens.

  2. Comprueba la identidad de cliente de una manera específica de la aplicación.

  3. Si el cliente se autentica correctamente, usa las interfaces de Cosmos DB (SDK o REST) para generar un nuevo token de tiempo limitado y lo devuelve al cliente.

Consulte también