Suporte a CWT para o CloudFront Functions - Amazon CloudFront

Suporte a CWT para o CloudFront Functions

Esta seção apresenta detalhes sobre o suporte a CBOR Web Tokens (CWT) no CloudFront Functions, o que permite autenticação e autorização seguras baseadas em tokens nos locais da borda do CloudFront. Esse suporte é fornecido como um módulo, acessível em sua função do CloudFront.

Para usar esse módulo, crie uma função do CloudFront usando o Runtime 2.0 do JavaScript e inclua a seguinte instrução na primeira linha do código da função:

import cf from 'cloudfront';

Os métodos associados a este módulo podem ser acessados por meio de cf.cwt.* (em que * é um curinga representando as diferentes funções presentes no módulo):

cf.cwt.*

Para ter mais informações, consulte Recursos de runtime 2.0 do JavaScript para CloudFront Functions.

No momento, o módulo aceita apenas a estrutura MAC0 com o algoritmo HS256 (HMAC-SHA256), com um limite de 1 KB para o tamanho máximo do token.

Estrutura do tokens

Esta seção aborda a estrutura de tokens que é esperada pelo módulo CWT. O módulo espera que o token seja corretamente marcado e identificável (p. ex., COSE MAC0). Além disso, para a estrutura de tokens, o módulo segue os padrões definidos pela CBOR Object Signing and Encryption (COSE) [RFC 8152].

( // CWT Tag (Tag value: 61) --- optional ( // COSE MAC0 Structure Tag (Tag value: 17) --- required [ protectedHeaders, unprotectedHeaders, payload, tag, ] ) )
exemplo : CWT usando a estrutura COSE MAC0
61( // CWT tag 17( // COSE_MAC0 tag [ { // Protected Headers 1: 4 // algorithm : HMAC-256-64 }, { // Unprotected Headers 4: h'53796d6d6574726963323536' // kid : Symmetric key id }, { // Payload 1: "https://iss.example.com", // iss 2: "exampleUser", // sub 3: "https://aud.example.com", // aud 4: 1444064944, // exp 5: 1443944944, // nbf 6: 1443944944, // iat }, h'093101ef6d789200' // tag ] ) )
nota

A tag CWT é opcional ao gerar tokens. No entanto, a tag da estrutura COSE é necessária.

Método validateToken()

A função decodifica e valida um CWT usando a chave especificada. Se o comando tiver êxito, ela exibirá um CWT decodificado. Do contrário, gerará um erro. Observe que essa função não valida o conjunto de instruções.

Solicitação

cf.cwt.validateToken(token, handlerContext{key})
Parâmetros
token (obrigatório)

Token codificado para validação. Deve ser um buffer em JavaScript.

handlerContext (obrigatório)

Um objeto JavaScript que armazena o contexto para a chamada validateToken. No momento, somente a propriedade key é permitida.

key (obrigatório)

Chave secreta para computação de resumo de mensagens. Pode ser fornecido como uma string ou como um buffer em JavaScript.

Resposta

Quando o método validateToken() exibe um token validado com êxito, a resposta da função é um CWTObject no formato a seguir. Depois de decodificadas, todas as chaves de solicitação são representadas como strings.

CWTObject { protectedHeaders, unprotectedHeaders, payload }

Exemplo: validar o token com kid enviado como parte do token

Este exemplo demonstra a validação de um CWT, em que kid (key ID) é extraído do cabeçalho. Em seguida, o kid é encaminhado ao KeyValueStore do CloudFront Functions para buscar a chave secreta usada para validar o token.

import cf from 'cloudfront' const CwtClaims = { iss: 1, aud: 3, exp: 4 } async function handler(event) { try { let request = event.request; let encodedToken = request.headers['x-cwt-token'].value; let kid = request.headers['x-cwt-kid'].value; // Retrieve the secret key from the kvs let secretKey = await cf.kvs().get(kid); // Now you can use the secretKey to decode & validate the token. let tokenBuffer = Buffer.from(encodedToken, 'base64url'); let handlerContext = { key: secretKey, } try { let cwtObj = cf.cwt.validateToken(tokenBuffer, handlerContext); // Check if token is expired const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds if (cwtObj[CwtClaims.exp] && cwtObj[CwtClaims.exp] < currentTime) { return { statusCode: 401, statusDescription: 'Token expired' }; } } catch (error) { return { statusCode: 401, statusDescription: 'Invalid token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } return request; }

Método generateToken()

Essa função gera um novo CWT usando a carga útil e as configurações de contexto fornecidas.

Solicitação

cf.cwt.generateToken(generatorContext, payload)
Parâmetros
generatorContext (obrigatório)

Esse é um objeto JavaScript usado como contexto para gerar o token e contém os seguintes pares de chave-valor:

cwtTag (opcional)

Esse valor é um booliano que, se for true, especifica que cwtTag deve ser adicionado.

coseTag (obrigatório)

Especifica o tipo de tag COSE. No momento, oferece suporte apenas a MAC0.

key (obrigatório)

Chave secreta para computar resumo de mensagens. Esse valor pode ser uma string ou Buffer em JavaScript.

payload (obrigatório)

Carga útil do token para codificação. A carga útil deve estar no seguinte formato CWTObject.

Resposta

Exibe um buffer em JavaScript contendo o token codificado.

exemplo : gerar um CWT
import cf from 'cloudfront'; const CwtClaims = { iss: 1, sub: 2, exp: 4 }; const CatClaims = { catu: 401, catnip: 402, catm: 403, catr: 404 }; const Catu = { host: 1, path: 2, ext: 3 }; const CatuMatchTypes = { prefix_match: 1, suffix_match: 2, exact_match: 3 }; const Catr = { renewal_method: 1, next_renewal_time: 2, max_uses: 3 }; async function handler(event) { try { const response = { statusCode: 200, statusDescription: 'OK', headers: {} }; const commonAccessToken = { protected: { 1: "5", }, unprotected: {}, payload: { [CwtClaims.iss]: "cloudfront-documentation", [CwtClaims.sub]: "cwt-support-on-cloudfront-functions", [CwtClaims.exp]: 1740000000, [CatClaims.catu]: { [Catu.host]: { [CatuMatchTypes.suffix_match]: ".cloudfront.net" }, [Catu.path]: { [CatuMatchTypes.prefix_match]: "/media/live-stream/cf-4k/" }, [Catu.ext]: { [CatuMatchTypes.exact_match]: [ ".m3u8", ".ts", ".mpd" ] } }, [CatClaims.catnip]: [ "[IP_ADDRESS]", "[IP_ADDRESS]" ], [CatClaims.catm]: [ "GET", "HEAD" ], [CatClaims.catr]: { [Catr.renewal_method]: "header_renewal", [Catr.next_renewal_time]: 1750000000, [Catr.max_uses]: 5 } } }; if (!request.headers['x-cwt-kid']) { throw new Error('Missing x-cwt-kid header'); } const kid = request.headers['x-cwt-kid'].value; const secretKey = await cf.kvs().get(kid); if (!secretKey) { throw new Error('Secret key not found for provided kid'); } try { const genContext = { cwtTag: true, coseTag: "MAC0", key: secretKey }; const tokenBuffer = cf.cwt.generateToken(commonAccessToken, genContext); response.headers['x-generated-cwt-token'] = { value: tokenBuffer.toString('base64url') }; return response; } catch (tokenError) { return { statusCode: 401, statusDescription: 'Could not generate the token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } }
exemplo : atualizar o token com base em alguma lógica
import cf from 'cloudfront' const CwtClaims = { iss: 1, aud: 3, exp: 4 } async function handler(event) { try { let request = event.request; let encodedToken = request.headers['x-cwt-token'].value; let kid = request.headers['x-cwt-kid'].value; let secretKey = await cf.kvs().get(kid); // Retrieve the secret key from the kvs // Now you can use the secretKey to decode & validate the token. let tokenBuffer = Buffer.from(encodedToken, 'base64url'); let handlerContext = { key: secretKey, } try { let cwtJSON = cf.cwt.validateToken(tokenBuffer, handlerContext); // Check if token is expired const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds if (cwtJSON[CwtClaims.exp] && cwtJSON[CwtClaims.exp] < currentTime) { // We can regnerate the token and add 8 hours to the expiry time cwtJSON[CwtClaims.exp] = Math.floor(Date.now() / 1000) + (8 * 60 * 60); let genContext = { coseTag: "MAC0", key: secretKey } let newTokenBuffer = cf.cwt.generateToken(cwtJSON, genContext); request.headers['x-cwt-regenerated-token'] = newTokenBuffer.toString('base64url'); } } catch (error) { return { statusCode: 401, statusDescription: 'Invalid token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } return request; }