CloudFront Functions の CWT サポート - Amazon CloudFront

CloudFront Functions の CWT サポート

このセクションでは、CloudFront Functions での CBOR ウェブトークン (CWT) のサポートについて詳しく説明します。これにより、CloudFront Edge Locations での安全なトークンベースの認証と承認が可能になります。このサポートはモジュールとして提供され、CloudFront Functions でアクセスできます。

このモジュールを使用するには、JavaScript ランタイム 2.0 を使用して CloudFront Functions を作成し、関数コードの最初の行に次のステートメントを含めます。

import cf from 'cloudfront';

このモジュールに関連付けられたメソッドには、次からアクセスできます (* はモジュール内に存在するさまざまな関数を表すワイルドカードです)。

cf.cwt.*

詳細については、「CloudFront Functions の JavaScript ランタイム 2.0 の機能」を参照してください。

現在、モジュールは HS256 (HMAC-SHA256) アルゴリズムを使用した MAC0 構造のみをサポートし、トークンの最大サイズは 1KB に制限されています。

トークン構造

このセクションでは、CWT モジュールで想定されるトークン構造について説明します。モジュールは、トークンが正しくタグ付けされ、識別可能であること (COSE MAC0 など) を想定しています。さらに、トークンの構造については、モジュールは 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, ] ) )
例 : COSE MAC0 構造を使用する CWT
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 ] ) )
注記

トークンを生成する場合、CWT タグはオプションです。ただし、COSE 構造タグは必要です。

validateToken() メソッド

関数は、指定されたキーを使用して CWT トークンをデコードし、検証します。検証が成功すると、デコードされた CWT トークンが返されます。それ以外の場合は、エラーをスローします。この関数はクレームセットを検証しないことに注意してください。

リクエスト

cf.cwt.validateToken(token, handlerContext{key})
パラメータ
トークン (必須)

検証用のエンコードされたトークン。これは JavaScript バッファである必要があります。

handlerContext (必須)

validateToken 呼び出しのコンテキストを保存する JavaScript オブジェクト。現在、 キープロパティのみがサポートされています。

キー (必須)

メッセージダイジェストの計算のシークレットキー。文字列または JavaScript バッファのいずれかとして指定できます。

応答

validateToken() メソッドが正常に検証されたトークンを返すと、関数からのレスポンスは次の形式の CWTObject になります。デコードされると、すべてのクレームキーが文字列として表されます。

CWTObject { protectedHeaders, unprotectedHeaders, payload }

例 – トークンの一部として送信された kid を使用してトークンを検証します

この例では、kid がヘッダーから抽出される CWT トークンの検証を示しています。その後、kid は CloudFront Functions KeyValueStore に渡され、トークンの検証に使用されるシークレットキーを取得します。

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; }

generateToken() メソッド

この関数は、提供されたペイロードとコンテキスト設定を使用して新しい CWT トークンを生成します。

リクエスト

cf.cwt.generateToken(generatorContext, payload)
パラメータ
generatorContext (必須)

これは、トークンを生成するためのコンテキストとして使用される JavaScript オブジェクトで、次のキーと値のペアを含みます。

cwtTag (オプション)

この値はブール値であり、true が指定されている場合は cwtTag を追加する必要があります。

coseTag (必須)

COSE タグタイプを指定します。現在のところ、MAC0 のみサポートされます。

キー (必須)

メッセージダイジェストを計算するシークレットキー。この値は、文字列または JavaScript Buffer のいずれかです。

ペイロード (必須)

エンコード用のトークンペイロード。ペイロードは CWTObject 形式である必要があります。

応答

エンコードされたトークンを含む JavaScript バッファを返します。

例 : 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' }; } }
例 : 一部のロジックに基づいてトークンを更新する
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; }