Claude 3.5 sonnetがCloudFormationを書くのに優秀だった
CloudFrontでCloudFront Functionsを使ってBASIC認証を実装するCloudFormationテンプレートを書いてください
というちょっとイマイチなプロンプトでGPT-4oとClaude 3.5 sonnetに聞いてみたら結構違いました。
関連記事
GPT-4o
AWSTemplateFormatVersion: '2010-09-09'
Resources:
CloudFrontDistribution:
Type: 'AWS::CloudFront::Distribution'
Properties:
DistributionConfig:
Origins:
- Id: myOrigin
DomainName: your-origin-domain-name
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: myOrigin
ViewerProtocolPolicy: redirect-to-https
FunctionAssociations:
- EventType: viewer-request
FunctionARN: !GetAtt BasicAuthFunction.FunctionARN
Enabled: true
BasicAuthFunction:
Type: 'AWS::CloudFront::Function'
Properties:
Name: 'BasicAuthFunction'
FunctionCode: |
function handler(event) {
var request = event.request;
var headers = request.headers;
// Username and password (base64 encoded)
var authString = 'Basic ' + 'YWRtaW46cGFzc3dvcmQ='; // replace 'YWRtaW46cGFzc3dvcmQ=' with your base64 encoded "username:password"
if (typeof headers.authorization === 'undefined' || headers.authorization[0].value !== authString) {
return {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: {
'www-authenticate': { value: 'Basic' }
}
};
}
return request;
}
CloudFrontFunctionIAMRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service: 'lambda.amazonaws.com'
Action: 'sts:AssumeRole'
Policies:
- PolicyName: 'CloudFrontFunctionPolicy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: 'arn:aws:logs:*:*:*'
Outputs:
CloudFrontDistributionId:
Value: !Ref CloudFrontDistribution
Description: 'The ID of the CloudFront distribution'
BasicAuthFunctionARN:
Value: !GetAtt BasicAuthFunction.FunctionARN
Description: 'The ARN of the Basic Auth CloudFront Function'
Claude 3.5 Sonnet
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFront distribution with Basic Auth using CloudFront Functions
Parameters:
Username:
Type: String
Description: Username for Basic Auth
Password:
Type: String
Description: Password for Basic Auth
NoEcho: true
Resources:
BasicAuthFunction:
Type: AWS::CloudFront::Function
Properties:
Name: basic-auth-function
AutoPublish: true
FunctionConfig:
Comment: Implement Basic Auth
Runtime: cloudfront-js-1.0
FunctionCode: !Sub |
function handler(event) {
var request = event.request;
var headers = request.headers;
var authString = '${Username}:${Password}';
var expectedAuth = 'Basic ' + btoa(authString);
if (typeof headers.authorization === 'undefined' || headers.authorization.value !== expectedAuth) {
return {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: {
'www-authenticate': { value: 'Basic' }
}
};
}
return request;
}
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
TargetOriginId: example-origin
FunctionAssociations:
- EventType: viewer-request
FunctionARN: !GetAtt BasicAuthFunction.FunctionARN
Origins:
- Id: example-origin
DomainName: example.com
CustomOriginConfig:
OriginProtocolPolicy: https-only
Outputs:
CloudFrontDomainName:
Description: Domain name of the CloudFront distribution
Value: !GetAtt CloudFrontDistribution.DomainName
比較
まず、Claudeの方はDescriptionがありますね。
GPTも場合によってはDescriptionを入れて返してくれるので、たまたまかもしれません
GPTあんまりCloudFormationに強くなさそう
GPTの方は'AWS::CloudFront::Function'に必須のプロパティが抜けてます。
Claudeの方にはちゃんと入ってます。
ここです。
FunctionConfig:
Comment: Implement Basic Auth
Runtime: cloudfront-js-1.0
ただ、私の疑問はなぜRuntimeにcloudfront-js-1.0を使ったのかというところです。
最新はcloudfront-js-2.0です。
Claudeに聞いてみました。
Q: なぜ、cloudfront-js-2.0でなくcloudfront-js-1.0を使用したのですか
ご質問ありがとうございます。確かに、より新しいバージョンの cloudfront-js-2.0 を使用する方が良い選択肢であったかもしれません。私の回答で cloudfront-js-1.0 を使用した理由を説明し、そして cloudfront-js-2.0 を使用する利点について説明します。
なぜ cloudfront-js-1.0 を使用したか:
互換性: 多くの既存の実装例やドキュメントが cloudfront-js-1.0 を使用しているため、互換性の観点から選択しました。
習慣: CloudFront Functions が最初にリリースされた時のバージョンであり、多くの開発者にとってなじみ深いものです。
なぜ cloudfront-js-2.0 を使用すべきだったか:
最新機能: より新しいバージョンには、パフォーマンスの向上や新しい機能が含まれている可能性があります。
将来性: 新しいバージョンはより長期的なサポートが期待できます。
セキュリティ: 新しいバージョンには、セキュリティの改善が含まれている可能性があります。cloudfront-js-2.0 の利点:
より多くの組み込み関数やAPIが利用可能である可能性があります。
パフォーマンスが向上している可能性があります。
今後追加される機能との互換性が高い可能性があります。テンプレートを改善するには、以下のように Runtime を変更することをお勧めします
素晴らしいですね。
あと、GPTの方は変なIAMロールが混じってますね
あとこれはjavascriptの間違いですが、GPTはここもおかしいですね
if (typeof headers.authorization === 'undefined' || headers.authorization[0].value !== authString)
headers.authorization.value
ですね
Claudeの方はちゃんとそうなってますね。
Claude気が利く
少し驚いたのが、Claudeの方は、Basic認証用のユーザー名とパスワードをパラメータで設定していることです。
しかもNoEcho: true
がついてますね
気が利きますね。
悪くいうとそんな指示はしていないということにもなりますが。
個人的にはこの気の利き方は好きです。
1聞いて10返ってきた方が、その10の中に自分のわからないことがあった場合、調べるきっかけになるので嬉しいです。
ただ、この回答、1つ気になるのが、CloudFront Functionsは実行可能時間がかなり短いというところです。Base64エンコーディングのbtoa()関数の実行時間がどれぐらいか?というところを考える必要があります。
関数コード内では、Base64エンコーディングにbtoa()関数を使用していますが、これはCloudFront Functionsの実行環境で利用可能です。
Claudeはこう言ってますが、本当かなと思うので実験してみます。
全然余裕でした。
ただ正直、個人的に毎回btoa関数走らせるのはしっくりこないのと、流石に平文のままコードにパスワードが入ってしまうのが嫌なので!Subと!Base64をうまく組み合わせてみました。
BasicAuthFunction:
Type: "AWS::CloudFront::Function"
Properties:
Name: "BasicAuthFunction"
FunctionConfig:
Comment: "Basic authentication"
Runtime: "cloudfront-js-2.0"
AutoPublish: true
FunctionCode: !Sub
- |
function handler(event) {
const request = event.request
const headers = request.headers
if (!headers.authorization || headers.authorization.value !== Basic "${AuthString}") {
return {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: {
'www-authenticate': { value: 'Basic' }
}
};
}
return request;
}
- AuthString: !Base64 {Fn::Sub: "${Username}:${Password}"}
これだとBase64エンコードした状態でコードに埋め込まれるのでまだマシです。
ハッシュじゃないので少しマシなぐらいですが。
あと少しJavascriptを今っぽくしました。
限定したユーザーしかそもそもコンソールにアクセスできないのと、BASIC認証を使うであろう場合は限定的だと考えるとこれで十分かなと思いますね。
まとめ
GPT有料会員だったのですが、やめてClaudeに引っ越ししました。
Discussion