カテゴリー
【AWS使い方ガイド】CloudFront FunctionsでS3バケット内のリソースのアクセス認証を掛ける方法
※ 当ページには【広告/PR】を含む場合があります。
2024/10/07


こんにちは!
$ curl -XGET https://xxxxxxxxxxxxx.cloudfront.net/greeting.txt
こんにちは!
$ curl -XGET https://xxxxxxxxxxxxxxxxx.s3.ap-northeast-1.amazonaws.com/greeting.txt
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>*********</RequestId><HostId>************</HostId></Error>
CloudFront Functions (Javascript Runtime 2.0)の話
+ 実装には独自の「Javascript Runtime」を使う
+ 作成されるCF2インスタンスのロケーションはCFディストリビューションの場所と同じ
+ ビューアーリクエストとビューアーレスポンスの2つの関数タイプしかない
async function handler(event) {
const request = event.request;
const clientIP = event.viewer.ip;
//クライアントのIP値をtrue-client-ipヘッダーとしてリクエストに追加する
request.headers['true-client-ip'] = {value: clientIP};
return request;
}
リクエストイベント構造 〜 CF2のリクエストにはBody(ペイロード)が存在しない
method:
リクエストされたHTTPメソッド(読み取り専用:値変更不可)
uri:
リクエストされたURL(の相対パス)
querystring:
リクエストされたクエリ文字列(のオブジェクト)
headers:
リクエストのHTTPヘッダー(を表すオブジェクト)
ただし、Cookieヘッダーは除外
cookies:
リクエストのCookie(を表すオブジェクト)
ヘッダーの内、Cookieヘッダーから取得されたもの
URLのクエリ文字列からパスコードを渡す方法
[関数] > [関数を作成]


[構築] > [関数コード]
[変更を保存]

//認証に失敗した際のレスポンス
const response401 = {
statusCode: 401,
statusDescription: 'Unauthorized'
};
function token_verify(token, key) {
//認証トークンが無い場合
if (!token) {
throw new Error('No token supplied');
}
//認証できない場合
if (!_verify(token, key)) {
throw new Error('Signature verification failed');
}
}
//認証のロジック
function _verify(input, key) {
return input === key;
}
async function handler(event) {
let request = event.request;
//tokenヘッダーが存在しない場合には認証失敗で返す
if (!request.querystring.token) {
console.log("No token supplied in the querystring");
return response401;
}
const token = request.querystring.token.value;
//認証用の秘密鍵
const secretKey = 'HOGE';
try {
token_verify(token, secretKey);
}
catch (e) {
console.log(e);
return response401;
}
//レスポンスからのtokenヘッダー値を空にする
delete request.querystring.token;
return request;
}
[発行]
[関数を発行]

[テスト]
[JSONを編集]

[保存]
{
"version": "1.0",
"context": {
"eventType": "viewer-request"
},
"viewer": {
"ip": "1.2.3.4"
},
"request": {
"method": "GET",
"uri": "/index.html",
"headers": {},
"cookies": {},
"querystring": {
"token": {
"value": "aaaaa"
}
}
}
}
[関数をテスト]

401 Unauthorized
token=aaaaa
token=HOGE

[ビヘイビア] > [ビヘイビアを作成]

[関数の関連付け]
[ビューワーリクエスト]
CloudFront Functions
[ビヘイビアを作成]
$ curl -i -XGET https://xxxxxxxxxx.cloudfront.net/greeting.txt
HTTP/2 401
...
$ curl -i -XGET https://xxxxxxxxxx.cloudfront.net/greeting.txt?token=aaaaa
HTTP/2 401
...
401
$ curl -i -XGET https://xxxxxxxxxx.cloudfront.net/greeting.txt?token=HOGE
HTTP/2 200
content-type: text/plain
...
こんにちは!
ヘッダーからパスコードを渡す方法
//認証に失敗した際のレスポンス
const response401 = {
statusCode: 401,
statusDescription: 'Unauthorized'
};
function token_verify(token, key) {
//認証トークンが無い場合
if (!token) {
throw new Error('No token supplied');
}
//認証できない場合
if (!_verify(token, key)) {
throw new Error('Signature verification failed');
}
}
//認証のロジック
function _verify(input, key) {
return input === key;
}
async function handler(event) {
let request = event.request;
//X-Auth-Tokenヘッダーが存在しない場合には認証失敗で返す
if (!request.headers['x-auth-token']) {
console.log("No Authrization supplied in the headers");
return response401;
}
const token = request.headers['x-auth-token'].value;
//認証用の秘密鍵
const secretKey = 'HOGE';
try {
token_verify(token, secretKey);
}
catch (e) {
console.log(e);
return response401;
}
//レスポンスからのX-Auth-Tokenヘッダー値を空にする
delete request.headers['x-auth-token'];
return request;
}
request.headers['x-auth-token']
X-Auth-Token
x-auth-token
#👇トークンが異なるためアクセス拒否
$ curl -i -XGET -H 'X-Auth-Token:aaaaaaaa' https://xxxxxxxxxx.cloudfront.net/greeting.txt
HTTP/2 401
...
#👇トークンが一致
$ curl -i -XGET -H 'X-Auth-Token:HOGE' https://xxxxxxxxxx.cloudfront.net/greeting.txt
HTTP/2 200
content-type: text/plain
...
こんにちは!
まとめ
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー