コンテンツにスキップ

AWS

一般

アクティブなリソースの確認

請求額アラート設定

  • IAMルートユーザーでログイン
  • IAM設定画面でユーザ名をクリック
  • 表示されるメニューから「請求ダッシュボード」をクリック
  • 画面左側のメニュー一覧にある「請求設定」をクリック
  • 「コスト管理設定」の中にある「無料利用枠の使用のアラートの受信」にチェック
  • その下のEメールアドレス欄に送信先のメールアドレスを指定
  • 「請求アラートを受け取る」にチェック

請求額アラート設定: 一定の請求額を超えそうな場合にメールを受信する方法

  • AWSマネジメントコンソールを開く
  • CloudWatchを開く
  • 「バージニア北部」リージョン(us-east-1)を選択
  • 画面左側のメニュー一覧にある「アラーム」の中の「請求」をクリック
  • 初期設定と追加設定の二通りある
    • 初期設定の場合
      • この表の下部中央にある「アラームの作成」ボタンをクリック
        • 表の右上にある「アラームの作成」ボタンではない
        • 「メトリクスと条件の指定」画面でアラーム設定
    • 追加設定の場合
      • 「アラームの作成」ボタンをクリック
      • 「メトリクスの選択」ウインドウを開く
      • 「請求(Billing)」をクリック
      • 「概算合計請求金額」をクリック
      • 通過が「USD」, メトリクス名が「EstimatedCharges」の項目にチェック
      • 「メトリクスの選択」をクリック
  • 画面を下にスクロールし「条件」の欄を表示
  • 「しきい値の種類」で「静的」を選択
  • 「「EstimatedCargesが次の時…」」で「より大きい>しきい値)」を選択
  • 「…よりも」ではメールを送信してもらうための基準額をUSドルで入力
  • 入力が完了したら「次へ」ボタンをクリック
  • 以下のアクションの設定画面の「通知」欄で「このアラーム状態が以下のとき…」は「アラーム状態」を選択
  • 「SNSトピックの選択」のラジオボタンは「新しいトピックの作成」を選択
  • 「新規トピックの作成中…」の「トピック名」はデフォルトのまま
  • 「通知を受け取るEメールエンドポイント…」にアラートメールの送信先を入力
  • 「トピックの作成」ボタンをクリック
  • メールアドレスが「Eメール(エンドポイント))」に表示されていることを確認
  • 「次へ」ボタンをクリック
  • 「説明の追加」画面の名前と説明で「一意の名前を定義」欄にアラーム名を入力
    • 必要に応じて「アラームの説明」のテキストエリアに説明文を入力
  • 「次へ」ボタンをクリック
  • プレビューと作成画面が表示される
  • ここまでの入力内容に問題がないことを確認
  • 「アラームの作成」ボタンをクリック
  • アラートメールの送信先として指定したメールアドレスの受信ボックスを確認
  • AWSから届いたメールに記載された認証リンク「Confirm subscription」をクリック
  • 設定完了
  • リージョンを戻す

短縮URLをAWSサービスを使って作る

  • .NETの「短縮URL作成」あたりを参照すること.

無料ドメインの取得

  • freenomを使うと無料のドメインが取得できる
  • Route53などの調査で使うには非常に便利

料金確認

Amplify

AWS Hands-on for Beginners(日本語)

CDK

インストール

1
npm install -g aws-cdk

ドキュメント・ハンズオン

1
npm install -g aws-cdk
  • AWS Toolkit for Visual Studio Code https://aws.amazon.com/jp/visualstudiocode/
  • AWS CDK, AWS SAM
  • https://aws.amazon.com/jp/serverless/patterns/pattern-design-examples/
  • RDS proxy
  • 請求アラート, Slack通知: AWS知識本参照 https://dev.classmethod.jp/articles/notify-slack-aws-billing/
  • LambdaからログをS3に吐き出す(追記し続ける)
  • https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-hands-on/
  • https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-1st-Step-2022-confirmation_849.html
  • https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-level-100/
  • https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Serverless-1-2022-reg-event.html?trk=aws_introduction_page
  • https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Serverless-3-2022-reg-event.html?trk=aws_introduction_page

Lambda・API Gateway+Dynamodbのサンプル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using Amazon.CDK;
using Amazon.CDK.AWS.APIGateway;
using Amazon.CDK.AWS.DynamoDB;
using Amazon.CDK.AWS.Lambda;
using Amazon.CDK.AWS.Logs;
using Constructs;
using AssetOptions = Amazon.CDK.AWS.S3.Assets.AssetOptions;

namespace CdkUrlShortener;

public class CdkUrlShortenerStack : Stack
{
    private new const string StackName = "cdk-url-shortener-stack";

    internal CdkUrlShortenerStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
    {
        var buildOption = new BundlingOptions
        {
            Image = Runtime.DOTNET_6.BundlingImage,
            User = "root",
            OutputType = BundlingOutput.ARCHIVED,
            Command = new[]
            {
                "/bin/sh",
                "-c",
                " dotnet tool install -g Amazon.Lambda.Tools" +
                " && dotnet build" +
                " && dotnet lambda package --output-package /asset-output/function.zip"
            }
        };

        var lambdaFunction = new Function(this, $"{StackName}-lambda-function", new FunctionProps
        {
            Runtime = Runtime.DOTNET_6,
            MemorySize = 1024,
            LogRetention = RetentionDays.ONE_DAY,
            Handler = "Function",
            Code = Code.FromAsset("lambda/Function/", new AssetOptions
            {
                Bundling = buildOption
            })
        });

        // キーが短縮URL、バリューがもとのURL
        var table = new Table(this, $"{StackName}-mapping-table", new TableProps
        {
            PartitionKey = new Attribute
            {
                Name = "id",
                Type = AttributeType.STRING
            },
            RemovalPolicy = RemovalPolicy.DESTROY
        });

        table.GrantReadWriteData(lambdaFunction);
        lambdaFunction.AddEnvironment("TABLE_NAME", table.TableName);

        // Proxy all request from the root path "/" to Lambda Function One
        var restApi = new LambdaRestApi(this, $"{StackName}-url-shortener-api", new LambdaRestApiProps
        {
            Handler = lambdaFunction,
            Proxy = true
        });

        var unused = new CfnOutput(this, $"{StackName}-api-gw-arn",
            new CfnOutputProps {Value = restApi.ArnForExecuteApi()});
    }
}

--require-approval never コマンド実行時にいちいちyを渡さないで済むようにする

1
cdk deploy --require-approval <LEVEL>

アップデート

1
2
3
npm i -g npm-check-updates
ncu -g aws-cdk
npm -g install aws-cdk@<ver>

コマンド init

1
2
cdk init sample-app --language csharp
cdk init sample-app --language python

コマンド diff: ローカルとデプロイの比較

1
cdk diff

コマンド deploy: スタックをデフォルトのアカウント・リージョンにデプロイ

コマンド ls: アプリ内のスタックを全て表示

コマンド docs: CDKドキュメントを開く

コマンド synth: CloudFormationテンプレート出力

1
cdk synth

特定環境のdeploy, destroy

  • Program.csで設定しているStackIDを指定してcdk deployまたはcdk destroyすればよい.
1
cdk deploy <stack-id>

バケットの削除

1
2
3
4
5
        // 削除時にs3のバケットも削除する
        _ = new Bucket(this, "WorkshopBucket", new BucketProps
        {
            RemovalPolicy = RemovalPolicy.DESTROY
        });

CLI

Session Managerでのポートフォワーディング, リモートホストへの接続

1
aws ssm start-session --target i-0759d9149c57b9e13
  • TODO CDKにする
  • PostgreSQLについてはPostgreSQLを参考にすること.
  • 注意
    • aws ssm start-sessionは(CDKで環境設定した)適切なアカウントで実行すること. 権限エラーで実行できず, An error occurred (TargetNotConnected) when calling the StartSession operation: <ssm-managed-instance-id> is not connected.というエラーが出る.
    • <remote-database-host-name>はエンドポイント名を入れればよい.
1
2
3
4
5
6
7
aws ssm start-session \
  --target <ssm-managed-instance-id> \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters '{"portNumber":["5432"],"localPortNumber":["1053"],"host":["<remote-database-host-name>"]}'


psql -h 127.0.0.1 -p 1053 -U pgadmin
1
2
3
4
5
6
7
aws ssm start-session \
  --target <ssm-managed-instance-id> \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters '{"portNumber":["3306"],"localPortNumber":["1053"],"host":["<remote-database-host-name>"]}'


mysql -h 127.0.0.1 --port 1053 -u admin -p

S3 バケット作成

  • 東京リージョンはap-northeast-1
1
2
3
4
aws s3api create-bucket \
--bucket <bucket-name> \
--region <region-name> \
--create-bucket-configuration LocationConstraint=<region-name>

アクセスキー取得

  • 参考: CloudShellを使うとローカルの設定なしでAWS CLIが使えるので必要に応じて使い分けよう
  • IAMユーザーのアクセスキーの管理
  • アクセスキーとシークレットキーをCSVで取得, メモ
  • 次のコマンド実行
1
2
3
4
aws configure

Default region name [None]: ap-northeast-1
Default output format [None]: json
  • 上記設定は~/.aws/configに次のように記録される
1
2
3
[default]
region = ap-northeast-1
output = json
  • ~/.aws/credentialsaws_access_key_idaws_secret_access_keyが記録される

アカウント確認

  • 下記のどちらかを実行する
1
2
aws sts get-caller-identity
aws configure list
  • ~/.aws/cli/aliaswhoamiとして登録しておくとよい.
1
2
[toplevel]
whoami = sts get-caller-identity

アカウント切り替え

1
2
aws configure list
export AWS_DEFAULT_PROFILE=<USER_NAME>

アカウント登録

  • 事前にAWSにアクセスしてIAMからアクセスキー・シークレットアクセスキーのCSVをダウンロードしておくこと
    • ~/.awsにでも置いておくとよい
  • 特に希望がない場合のリージョンとフォーマット
    • リージョン: ap-northeast-1
    • フォーマット: json
1
2
aws configure --profile <username>
cat ~/.aws/credentials

補完設定

Cloud9

GitHub連携

  • 参考
  • 次のコマンドでSSH鍵を作成
1
2
3
cd ~/.ssh
ssh-keygen
less ~/.ssh/id_rsa.pub
  • GitHubに公開鍵を登録
  • リポジトリ作成
  • git pullしてコミット・プッシュ
  • push/pullについて詳しくは都度ググる

VSCodeでのSSH設定

VSCode参照.

コンソールでサービスを立ち上げたあとにブラウザで確認

  • 参考
    • Preview (プレビュー) > Preview Running Application (実行中のアプリケーションのプレビュー)
    • エディタに出てきたタブの右上, 四角の中に右上矢印があるボタンをクリック
    • ブラウザの別タブで画面が開く

CloudFormation

ドリフトの検出と解決

  • 実体とスタックの乖離をドリフトと呼ぶ
  • インポートで実体をスタックに取り込める

Copilot

公式ドキュメント

アカウント選択

  • copilot env initを実行するとそのappに紐づけるアカウント(profile)が設定できる

アカウント内に作成されたApplicationの一覧を確認したい

  • copilot app ls
  • 現在のアカウント・リージョン内にある全てのApplicationを確認

Applicationに含まれる対象を確認したい

  • copilot app show
  • Application内のServiceEnvironmentを含んだサマリ情報を表示

app init --domainのための事前設定

  • URL
  • Route 53コンソールからホストゾーンを新たに作る
  • 4つのNSレコードをAWSコンソールからコピー
  • 適切なレジストラのページに移動して4つのカスタムネームサーバーを張りつける
    • お名前.comでは次の通り: 参考
    • トップメニュー「ドメイン設定」を選ぶ
    • 左メニュー「ネームサーバーの設定 > ネームサーバーの変更」を選ぶ.
    • 適切なドメインを選択してチェックを入れる
    • 「他のネームサーバーを利用」タブを選ぶ.
    • AWSコンソールで表示されたネームサーバー情報を入力する.

CloudFormationファイルを生成する

  • copilot <subcommand> package -hでヘルプを見よう.
  • 具体的には次のようなコマンドでymlが出力できる.
1
copilot job package -n dbmigrate -e staging --output-dir ./infrastructure

Environmentの作成

  • copilot env init

Environmentのデプロイ

  • 必要に応じて手動でcopilot/environments/[env name]/manifest.ymlを修正する
  • copilot env deploy

healthcheck

1
2
3
4
5
6
7
8
  healthcheck:
    path: "/health"
    healthy_threshold: 2
    unhealthy_threshold: 2
    interval: 10s
    timeout: 5s
    grace_period: 60s
  deregistration_delay: 60s

init中にターミナルが死んで再作成・削除できなくなったとき

  • 別のアプリを作ってみる.
  • 作ったときに出てくるメッセージをもとにAWSコンソールからサービスを確認する.
  • 作ったアプリに対するモノが何かできているはずで, それを直接削除する.
    • 例えばCloudFormationのスタックができているはずだから, それを削除する.

pipelineによるマイグレーション

Load Balanced Web Serviceのプロパティのリスト

  • どこにあるかすぐ忘れるため記録
  • manifestにある

Load Balanced jobでデータベースをマイグレーションしたい

  • AWSコンソールでSecrets Managerにアクセスする
  • 対応するRDS用のシークレットの名前を控える
  • jobymlsecretsに次のように設定する
    • secretsmanagerの値は控えた値を書く
1
2
3
secrets:
  CLUSTER_SECRET:
    secretsmanager: 'mydjangodbAuroraSecret-ObSZ2fGHWHTm'

Load Balanced ドメイン設定: DNSプロバイダーはお名前.comなど外部プロバイダー

  • GitHub copilot-domainで実験してある.
  • 念のため転記.
  • 注意
    • 記述を明確にするためドメインはacademic-event.comとしている. これを書き換えれば当然書き換えたドメインで設定できる.
    • AWSのアカウントもexport AWS_DEFAULT_PROFILE=<aws-account-name>で適切に設定すること.
  • copilotでのLoad Balancedへのドメイン設定確認用:特にDNSプロバイダーはお名前.comなど外部サービスの場合
  • 参考:DNS での検証
    • AWS Certificate Managerでパブリック証明書をリクエスト
    • 完全修飾ドメイン名で*.academic-event.comを設定
    • AWSで要求された値をCNAMEお名前.comに設定
      • .acm-validations.aws.のように末尾が.acm-validations.aws.になっている値をCNAMEValueに設定する
      • 特にACMCNAME名お名前.comホスト名に、 ACMCNAME値お名前.comVALUEに入力する
    • AWSで対応する証明書のステータスが成功になるか確認:最大三日待つ
    • 証明書のARNを控える
  • Copilotへの設定は以下の通り
    • 重要 copilot env init --import-cert-arns <ACMのARN>で初期化する必要がある
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
export AWS_DEFAULT_PROFILE=<aws-account-name>
copilot app init pt-domain
copilot env init --name test \
  --profile <aws-account-name> \
  --app pt-domain \
  --default-config \
  --import-cert-arns <ACMの値を設定>
copilot svc init --name pt-domain \
  --svc-type "Load Balanced Web Service" \
  --dockerfile ./Dockerfile \
  --port 80
copilot env deploy --name test
copilot svc deploy --env test
copilot svc show
1
2
3
4
5
6
export AWS_DEFAULT_PROFILE=<aws-account-name>
copilot env init --name stg \
  --profile <aws-account-name> \
  --app pt-domain \
  --default-config \
  --import-cert-arns <ACMの値を設定>
  • copilot/stg/manifest.ymlaliasを設定
  • copilot/pt-domain/manifest.ymlenvironmentsaliasを設定
1
2
copilot env deploy --name stg
copilot svc deploy --env stg
  • appに対するmanifest.ymlに対して次のような設定を追加する.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
http:
  alias: "www.academic-event.com"

environments:
  stg:
    http:
      alias: "stg.academic-event.com"
  test:
    http:
      alias: "www.academic-event.com"
  • environments配下のmanifest.ymlに次のような設定を追加する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
http:
  public:
    # 適切なACMの値
    certificates: [<ACMの適切な値>]
  alias: "www.academic-event.com"


http:
  public:
    # 適切なACMの値
    certificates: [<ACMの適切な値>]
  alias: "stg.academic-event.com"
  • 下記コマンドで一通り設定・デプロイ
1
2
3
export AWS_DEFAULT_PROFILE=<aws-account-name>

nslookup -type=NS academic-event.com # お名前.comのDNSが表示されるか確認
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
export AWS_DEFAULT_PROFILE=<aws-account-name>
copilot app init pt-domain
copilot env init --name test \
  --profile <aws-account-name> \
  --app pt-domain \
  --default-config \
  --import-cert-arns <ACMの値を設定>
copilot svc init --name pt-domain \
  --svc-type "Load Balanced Web Service" \
  --dockerfile ./Dockerfile \
  --port 80
copilot env deploy --name test
copilot svc deploy --env test
copilot svc show
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
export AWS_DEFAULT_PROFILE=<aws-account-name>
copilot env init --name stg \
  --profile <aws-account-name> \
  --app pt-domain \
  --default-config \
  --import-cert-arns <ACMの値を設定>


copilot env deploy --name stg
copilot svc deploy --env stg
  • お名前.comCNAMEを追加する
    • 追加するCNAMEレコードのホスト名に対応する値はALBDNS名を指定する.
    • ALBDNS名は以下の参考資料を参照すること.
      • copilotで生成したならcopilot svc showCOPILOT_LB_DNSでも確認できる.
    • Creating records by using the Amazon Route 53 console
    • 下記項目を参考にDNS NameCNAMEとして設定すればよい.
      • AWSマネジメントコンソールにログインする
      • EC2のコンソールにアクセスする
      • ナビゲーションペインでLoad Balancersを選ぶ
      • ロードバランサーのリストでエイリアスレコードを作りたい対象を選ぶ
      • DescriptionタブでDNS nameを確認する

Request Driven jobでデータベースをマイグレーションしたい

  • copilot svc showでデータベース接続用情報を持つSECRET ARNの値を確認する.
  • copilot job initで適切に設定する
  • ymlを編集する
    • schedulenoneにする
    • シークレット変数を追加する.
1
2
3
secrets:
  # 変数名と値は`copilot svc show`の値を指定する
  WEBCLUSTER_SECRET_ARN: "arn:aws:secretsmanager:us-west-2:573143736992:secret:webclusterAuroraSecret-5ggcmKflNSGA-UR8O44"
  • copilot job deployする
  • copilot job runのあとCloudWatchのログを確認する

C#の参考プログラム

1
dotnet add package AWSSDK.SecretsManager.Caching
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System.Text.Json;
using Amazon.SecretsManager.Extensions.Caching;
using CopilotRequestDriven.Models;

namespace CopilotRequestDriven.Services;

public class DbConnectionStringService
{
    public async Task<string> GetConnectionString(string secretArn)
    {
        var cache = new SecretsManagerCache();
        string secretString;
        try
        {
            secretString = await cache.GetSecretString(secretArn);
            if (secretString == null)
            {
                Console.WriteLine("secretString is null");
                return "Cannot get a secret string";
            }
        }
        catch (Exception e)
        {
            // ジョブの場合は直接JSONの値が入るようでHTTPアクセスでエラーが出るため`secretArn`で置き換える
            secretString = secretArn;
        }
        Console.WriteLine($"secretString: {secretString}");
        var secret = JsonSerializer.Deserialize<AwsAuroraSecret>(secretString);
        return
            $"User ID={secret!.username};Password={secret.password};Host={secret.host};Port={secret.port};Database={secret.dbname};";
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
using HogeApp.Services;

var secretArn = Environment.GetEnvironmentVariable("WEBCLUSTER_SECRET_ARN");
var dbConnection = new DbConnectionStringService();
Console.WriteLine($"secretArn: {secretArn}");
var defaultConnection = builder.Configuration.GetConnectionString("DefaultConnection");
var connectionString = secretArn is null
    ? defaultConnection ?? "should not empty"
    : await dbConnection.GetConnectionString(secretArn);
Console.WriteLine($"Connection String: {connectionString}");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseNpgsql(connectionString));

Request Driven 2023-02-10時点でのエラー

1
2
 Proposing infrastructure changes for stack my-app-test-my-svc
 deploy service my-svc to environment test: deploy service: check if changeset is empty: create change set copilot-ceee385b-d1d7-4248-b4f9-a9a725daab12 for stack my-app-test-my-svc: ValidationError: Template format error: Unrecognized resource types: [AWS::AppRunner::Service]
  • 2023-02-10時点ではus-west-1ではApp Runnerが使えない模様

svc デプロイ

  • 新しいEnvironmentを作った時点でデプロイされたServiceはない.
  • デプロイしたいServiceのディレクトリからcopilot deployコマンドを実行する.
  • どのEnvironmentにデプロイしたいのか尋ねられる

svc サービスに含まれる対象を確認したい

  • copilot svc show

svc 起動中のサービス確認, copilot svc status

  • URL
  • copilot svc status

copilot svc exec

  • URL
  • Fargatedocker exec対応
  • 2023-03時点ではLoad Balancedでは使えるがApp Runnerでは使えない

CloudFormationテンプレートの出力

1
copilot svc package

pipeline

1
2
copilot pipeline init
copilot pipeline update

storage environmentごとにアクセス設定を変える

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Mappings:
  PublicAccessibilityMap:
    test:
      "publiclyAccessible": true
    prod:
      "publiclyAccessible": false
[name]DBCluster:
  Metadata:
    'aws:copilot:description': 'The testing Aurora Serverless v2 database cluster'
  Type: 'AWS::RDS::DBCluster'
  Properties:
    PubliclyAccessible: !FindInMap [PublicAccessibilityMap, !Ref Env, publiclyAccessible]

環境変数やSecretsが反映されない

  • 2023-05-24, C#ASP.NETを使っていたときの話.
  • Dockerfilemanifest.ymlの両方でASPNETCORE_ENVIRONMENTを指定していたら, 正しく環境変数に反映されていなかった.
  • DockerfileからENV指定を削除して対応した.

秘密の変数の指定

  • 2022-12-20 AWS Copilot with AWS CDK
  • 適切なyamlファイルにsecretsを指定する
  • 下記のように書く
    • PostgreSQLConfig__Hostは自由にしてよく, この値がコンテナに環境変数として指定される
    • AuroraSecret-ABC3G7c8bvFyP-C5JIGEcopilot svc showSecretsに表示される値から取れる
    • host::にあたる部分はAWSコンソールなどでデータベースのシークレット変数として指定されている変数名を取ればよい
1
2
3
4
5
6
7
environments:
  staging:
    image:
      build: Dockerfile.staging
    secrets:
      PostgreSQLConfig__Host:
        secretsmanager: 'AuroraSecret-ABC3G7c8bvFyP-C5JIGE:host::'

削除, 特にcopilot job deleteが正しく完了しない場合

  • これまでの経験上のまとめ
  • 時々jobが実行中のままになっている場合がある.
    • 特にjob作成時にデータベース接続に失敗していたとき.
  • job deleteが失敗したら, CloudFormationを調べ, 特にState Machineを調べよう.
  • 実行中のjobがある場合は停止させる.
  • 停止してから改めてコマンド実行してみよう.

セキュリティグループを調べる

  • AWSのコンソールにアクセスする
  • VPCにアクセスする
  • ダッシュボードから「セキュリティ グループ」を選ぶ
  • 設定されたセキュリティ グループの一覧が表示されている

サービスに設定された環境変数の値を確認する

  • copilot svc showSecretsで確認できる

サービスのコンテナへのコマンド実行

1
copilot svc exec

サービスの停止・再開

1
2
3
copilot svc pause -n maitred

copilot svc resume -n maitred

ジョブ実行

1
2
copilot job run
copilot job run --name db-migrate --env staging

データベース接続: App Runner

1
2
3
network:
  vpc:
    placement: private
  • copilot storage initを実行する
  • copilot svc showでデータベース接続用のSECRET ARNの値を確認する
  • 確認した値をもとにcopilot/svc/addonsに次のような内容でiam-secrets-manager-policy.ymlを追加する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Parameters:
  App:
    Type: String
    Description: Your application's name.
  Env:
    Type: String
    Description: The environment name your service, job, or workflow is being deployed to.
  Name:
    Type: String
    Description: The name of the service, job, or workflow being deployed.

Resources:
  IamSecretsManagerPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Sid: ListBucketActions
          Effect: Allow
          Action:
            - secretsmanager:GetResourcePolicy
            - secretsmanager:GetSecretValue
            - secretsmanager:DescribeSecret
            - secretsmanager:ListSecretVersionIds
          Resource: "!!!取得した値で更新!!!"

Outputs:
  ListBucketPolicyArn:
    Description: "The ARN of the ManagedPolicy to attatch to the task role."
    Value: !Ref IamSecretsManagerPolicy
  • 環境変数APRDJANGOWEBCLUSTER_SECRET_ARNをもとにデータベース情報を取得するように設定する
データベース取得方法
JavaScript
  • 環境変数名は適切に設定すること
1
2
3
4
5
6
    const AWS = require('aws-sdk');
    const client = new AWS.SecretsManager({
        region: process.env.AWS_DEFAULT_REGION,
    });
    const dbSecret = await client.getSecretValue({SecretId: process.env.APRDJANGOWEBCLUSTER_SECRET_ARN}).promise();
    const {username, host, dbname, password, port} = JSON.parse(dbSecret.SecretString);
Python
  • 環境変数名は適切に設定すること
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os
import json

secret_arn = os.getenv("APRDJANGOWEBCLUSTER_SECRET_ARN")
if secret_arn is None:
    print("Since `secret_arn` is None, we use sqlite!")
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
else:
    print("secret_arn is not None!")
    print(f"secret_arn: {secret_arn}")
    DBINFO = json.loads(secret_arn)
    print(f"DBINFO: {DBINFO}")

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'HOST': DBINFO['host'],
            'PORT': DBINFO['port'],
            'NAME': DBINFO['dbname'],
            'USER': DBINFO['username'],
            'PASSWORD': DBINFO['password'],
        }
    }
C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class DbConnectionStringService
{
    public async Task<string> GetConnectionString(string secretArn)
    {
        var cache = new SecretsManagerCache();
        var secretString = await cache.GetSecretString(secretArn);
        if (secretString == null)
        {
            Console.WriteLine("secretString is null");
            return "Cannot get a secret string";
        }
        Console.WriteLine($"secretString: {secretString}");
        var secret = JsonSerializer.Deserialize<AwsAuroraSecret>(secretString);
        return
            $"User ID={secret!.username};Password={secret.password};Host={secret.host};Port={secret.port};Database={secret.dbname};";
    }
}
1
2
3
4
5
6
7
8
9
// Program.cs
var secretArn = Environment.GetEnvironmentVariable("WEBCLUSTER_SECRET_ARN");
var dbConnection = new DbConnectionStringService();
Console.WriteLine($"secretArn: {secretArn}");
var defaultConnection = builder.Configuration.GetConnectionString("DefaultConnection");
var connectionString = secretArn is null
    ? defaultConnection ?? "should not empty"
    : await dbConnection.GetConnectionString(secretArn);
Console.WriteLine($"Connection String: {connectionString}");

データベース接続: Load Balanced

  • 参考
  • copilot svc showSecretsを調べる
  • データベース用の値を控える: 例えばMYDJANGODB_SECRETなどデータベース用に設定した値_SECRETのような値になっているはず
    • これが環境変数に指定されているため使っている言語に合わせて環境変数を取得する
  • 環境変数はJSON形式の文字列だからJSONで解釈して接続文字列や接続情報を指定する
    • JSONの形式はAWSコンソールのSecrets Managerで確認できる
  • Djangoでの書き方は次の通り
    • ローカル開発やチェック用のログ出力も入れてある
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import os
import json

dbsecret = os.environ.get('MYDJANGODB_SECRET')
if dbsecret is None:
    print("Since `dbsecret` is None, we use sqlite!")
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
else:
    print("dbsecret is not None!")
    print(dbsecret)
    DBINFO = json.loads(dbsecret)
    print(DBINFO)
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'HOST': DBINFO['host'],
            'PORT': DBINFO['port'],
            'NAME': DBINFO['dbname'],
            'USER': DBINFO['username'],
            'PASSWORD': DBINFO['password'],
        }
    }

データベース接続: マイグレーションなどでジョブからつなぐ

  • 参考
  • 基本的なデータベースまでのサービス構築は他の項目を参照すること.
  • ジョブからデータベースにつなぐにはセキュリティ設定を追加する
  • 以下の記述でファイル名・項目名は構築したサービスごとに適切に設定すること
  • 特にsvc/addons/db.ymlDBClusterSecurityGroupに次のように追記する
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  mydjangodbDBClusterSecurityGroup: # 適切な項目を選ぶ
    Metadata:
      'aws:copilot:description': 'A security group for your Aurora Serverless v2 cluster mydjangodb'
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: The Security Group for the Aurora Serverless v2 cluster.
      SecurityGroupIngress:
        - ToPort: 5432
          FromPort: 5432
          IpProtocol: tcp
          Description: !Sub 'From the Aurora Security Group of the workload ${Name}.'
          SourceSecurityGroupId: !Ref mydjangodbSecurityGroup
        - ToPort: 5432                                                                                 # ADD
          FromPort: 5432                                                                               # ADD
          IpProtocol: tcp                                                                              # ADD
          Description: 'Access to environment security group'                                          # ADD
          SourceSecurityGroupId: { 'Fn::ImportValue': !Sub '${App}-${Env}-EnvironmentSecurityGroup' }  # ADD

メタデータ

  • URL
  • System Manager Parameter Storeに保存される
  • /copilot/applications/${app_name}に保存

リソース作成

  • URL
  • addonsの形でCloudFormationテンプレートを使えばCopilotと連携できる

DynamoDB

参考文献

参考: Amazon DynamoDB Labs

1
curl -sL https://amazon-dynamodb-labs.com/static/game-player-data/battle-royale.tar | tar -xv

DynamoDB Local

SDKによるアクセス方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
using System.Text.Json.Serialization;
using Amazon.DynamoDBv2.DataModel;

namespace Function.Entity;

[DynamoDBTable("mapping-table")]
public class MappingTable
{
    [JsonPropertyName("id")]
    [DynamoDBHashKey]
    public string Id { get; set; } = default!;

    [JsonPropertyName("targetUrl")]
    [DynamoDBRangeKey]
    public string TargetUrl { get; set; } = default!;
}
  • AmazonDynamoDBClientを使ったアクセス
    • DynamoDBの開発ガイドのチュートリアルで紹介されている
    • 取得できるItemsのクラスはList<Dictionary<string, AttributeValue>>
    • 自分で適切なオブジェクトにマップする必要がある.
    • URL短縮サービスでの次のコントローラー参照

モデリング例

  • MicrosoftNorthwindDynamoDBでモデル化: URL
  • 階層構造を持つ場合の例: Hierarchical Data

ECR

M1 Macx86_64ビルドしてプッシュする

  • ECRのコンソールにアクセスする.
  • 適切なイメージを選ぶ.
  • 画面上部の「プッシュコマンドの表示」をクリックする.
  • モーダル中のコマンドを順に熟考すればよい.
  • x86_64ビルドコマンドはDockerを参照すること.

MacError saving credentials: error storing credentials - err: exit status 1, out:Post "http://ipc/registry/credstore-updated": dial unix backend.sock: connect: no such file or directory``

  • URL
  • MacからECR認証トークンを取得し、レジストリに対して Docker クライアントを認証しますのプッシュをしようとしたらタイトルのエラーが出た
  • ~/.docker/config.jsoncredsStoredesktopだったのをosxkeychainにしたら通った

IAM

AdministratorAccess権限を与えたい

  • 「アクセス権限の追加」をクリック
  • 「既存のポリシーを直接アタッチ」をクリック
  • 「ポリシー名」を選ぶ

MFA設定 機種変更時にMFA端末を変更

ユーザー作成

ルートアカウントへのMFAを複数人に展開

  • ルートアカウントのMFAを複数設定できるようになったため, 実際に複数人に設定してもらい, 適切な権限を持つ人にルートアカウントを触れるようにしたい.
  • MFA設定
    • IAMの画面にアクセスしてから画面右の「クイックリンク > 自分の認証情報」リンクから画面遷移する.
    • その画面でQRコード読み取りして設定できる.
  • 対処1: リアルで複数名が集まれる
    • このときは既にルートアカウントにアクセスできる人が実際にIAM画面にアクセスし, MFA設定のQRコード読み取り部分をその人の画面から設定して試せばよい.
  • 対処2: リモートで対応したい.
    • ルートアカウントの情報は適切な形で共有してあり, 複数名がMFA以外の情報にはアクセスできるとする.
    • MFA認証のところまでログインを進める.
    • MFA認証できる人にネット上で依頼してMFAコードを送ってもらう.
    • ログインしてもらったあと, その人が対応しやすいMFA設定をしてもらう.

ロールのリスト取得

1
aws iam list-roles

MFA デバイス解除

Lambda

公式デベロッパーガイド

AWSサービスごとの請求額をSlackに通知する

SAM

ドキュメント

APIをローカルでホストする

1
sam local start-api

Create pipeline

1
sam pipeline init --bootstrap

initランタイム指定

1
sam init --runtime nodejs

エラーが出たとき

  • SAMはCloudFormationの拡張
  • SAMのビルドでエラーが出たときCloudFormationのログも確認しよう

公式リポジトリの実装例

コンテナを使ってビルド

1
sam build --use-container

資料集

SDK

S3で署名つきURL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// IAwsS3FileUpload
public interface IAwsS3FileUpload
{
    /// <summary>
    ///     `durationHours`で指定された時間の分だけ、
    ///     `objectKey`で指定されたファイルにアクセスする証明付きURLを生成する。
    /// </summary>
    /// <param name="objectKey">署名付きURLでアクセスさせるオブジェクトの名前</param>
    /// <param name="durationHours">時間(hour)指定でのURLの有効期間</param>
    /// <returns></returns>
    string GetPreSignedUrl(string objectKey, double durationHours);
}

// AwsS3FileUpload.cs
using Amazon.S3;
using Amazon.S3.Model;
using Models;
using Services.Interfaces;

public class AwsS3FileUpload : IAwsS3FileUpload
{
    private readonly IAmazonS3 _s3Client;
    private readonly IConfiguration _configuration;

    public AwsS3FileUpload(
        IAmazonS3 s3Client,
        IConfiguration configuration)
    {
        _s3Client = s3Client;
        _configuration = configuration;
    }

    public string GetPreSignedUrl(string objectKey, double durationHours)
    {
        var bucketName = _configuration.GetValue<string>(Constants.ApBucketName);
        var request = new GetPreSignedUrlRequest
        {
            BucketName = bucketName,
            Key = objectKey,
            Expires = DateTime.UtcNow.AddHours(durationHours),
        };
        return _s3Client.GetPreSignedURL(request);
    }
}

Secrets Manager

値を取る

  • 実際にコンソールでアクセスすると, 下の方にサンプルコードがある.
  • これを参考にすればよい.

SES

メール送信

  • GitHubを参考にすればよい.
  • AWS SDKを使う場合はIAMのアクセスキー・シークレットキーを使う.