

# Canary の一般的な機能
<a name="CloudWatch_Synthetics_Canaries_CommonFeatures"></a>

次の機能はすべての Canary ランタイムで使用できます。

## 環境変数
<a name="CloudWatch_Synthetics_Environment_Variables"></a>

Canary を作成する際に環境変数を使用できます。単一の Canary スクリプトを記述し、そのスクリプトをさまざまな値とともに使用すれば、1 つの同様のタスクに対して複数の Canary をすばやく作成できます。

たとえば、さまざまなソフトウェア開発ステージに `prod`、`dev`、`pre-release` などのエンドポイントがあるとします。各エンドポイントをテストするには、Canary を作成する必要があります。ソフトウェアをテストする単一の Canary スクリプトを記述できます。次に、3 つの Canary のそれぞれを作成するときに、異なるエンドポイント環境変数値を指定します。Canary を作成するときに、そのスクリプトと環境変数値を指定します。

環境変数の名前には、文字、数字、およびアンダースコアを使用できます。文字で始まり、少なくとも 2 文字である必要があります。環境変数の合計サイズは 4 KB を超えることはできません。Lambda の予約済み環境変数を環境変数の名前として指定することはできません。予約済み環境変数の詳細については、「[ランタイム環境変数](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime)」をご参照ください。

**環境変数はクライアント側で暗号化されません**  
AWS では、デフォルト設定により、環境変数のキーと値が保存時に AWS 所有のキーを使用して暗号化されます。ただし、CloudWatch Synthetics はクライアント側の暗号化を適用しません。機密情報は、転送中に暗号化した後にのみ保存します。詳細については、「[転送中の環境変数の暗号化](#CloudWatch_Synthetics_transit_encryption)」を参照してください。カスタマーマネージド AWS KMS キーを使用して、保存中の Canary の環境変数を暗号化することもできます。詳細については、「[カスタマーマネージド型キーを使用した環境変数の保存時の暗号化](#CloudWatch_Synthetics_function_encryption)」を参照してください。

次のスクリプト例では、2 つの環境変数を使用しています。このスクリプトは、ウェブページが利用可能かどうかをチェックする Canary 用です。環境変数を使用して、チェックする URL と、使用する CloudWatch Synthetics ログレベルの両方をパラメータ化します。

次のスニペットは、以下に示す完全なスクリプトの一部です。

次の関数は、`LogLevel` を `LOG_LEVEL` 環境変数の値に設定します。

```
 synthetics.setLogLevel(process.env.LOG_LEVEL);
```

この関数は、`URL` を `URL` 環境変数の値に設定します。

```
const URL = process.env.URL;
```

次の完全なスクリプトは、両方の環境変数を示しています。このスクリプトを使用して Canary を作成するときは、`LOG_LEVEL` および `URL` 環境変数の値を指定します。

```
var synthetics = require('@aws/synthetics-puppeteer');
const log = require('@aws/synthetics-logger');

const pageLoadEnvironmentVariable = async function () {

  // Setting the log level (0-3)
  synthetics.setLogLevel(process.env.LOG_LEVEL);
  // INSERT URL here
  const URL = process.env.URL;

  let page = await synthetics.getPage();
  //You can customize the wait condition here. For instance,
  //using 'networkidle2' may be less restrictive.
  const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000});
  if (!response) {
      throw "Failed to load page!";
  }
  //Wait for page to render.
  //Increase or decrease wait time based on endpoint being monitored.
  await page.waitFor(15000);
  await synthetics.takeScreenshot('loaded', 'loaded');
  let pageTitle = await page.title();
  log.info('Page title: ' + pageTitle);
  log.debug('Environment variable:' + process.env.URL);

  //If the response status code is not a 2xx success code
  if (response.status() < 200 || response.status() > 299) {
      throw "Failed to load page!";
  }
};

exports.handler = async () => {
  return await pageLoadEnvironmentVariable();
};
```

### 環境変数をスクリプトに渡す
<a name="CloudWatch_Synthetics_Canaries_pass_variables"></a>

コンソールで Canary を作成するときに環境変数をスクリプトに渡すには、コンソールの [**Environment variables**] (環境変数) セクションで環境変数のキーと値を指定します。詳細については、「[Canary を作成する](CloudWatch_Synthetics_Canaries_Create.md)」を参照してください。

API または AWS CLI を介して環境変数を渡すには、`RunConfig` セクションの `EnvironmentVariables` パラメータを使用します。以下は、キー `Environment` とキー `Region` を持つ 2 つの環境変数を使用する Canary を作成する AWS CLI コマンドの例です。

```
aws synthetics create-canary --cli-input-json '{
 "Name":"nameofCanary",
 "ExecutionRoleArn":"roleArn",
 "ArtifactS3Location":"s3://amzn-s3-demo-bucket-123456789012-us-west-2",
 "Schedule":{
    "Expression":"rate(0 minute)",
    "DurationInSeconds":604800
 },
 "Code":{
    "S3Bucket": "canarycreation",
    "S3Key": "cwsyn-mycanaryheartbeat-12345678-d1bd-1234-abcd-123456789012-12345678-6a1f-47c3-b291-123456789012.zip",
    "Handler":"pageLoadBlueprint.handler"
 },
 "RunConfig": {
    "TimeoutInSeconds":60,
    "EnvironmentVariables": {
       "Environment":"Production",
       "Region": "us-west-1"
    }
 },
 "SuccessRetentionPeriodInDays":13,
 "FailureRetentionPeriodInDays":13,
 "RuntimeVersion":"syn-nodejs-2.0"
}'
```

## カスタマーマネージド型キーを使用した環境変数の保存時の暗号化
<a name="CloudWatch_Synthetics_function_encryption"></a>

デフォルトでは、AWS 所有キーにより保存中の Canary 環境変数が暗号化されます。カスタマーマネージド AWS KMS キーを指定して、保存中の Canary 環境変数を暗号化できます。カスタマーマネージドキーを使用すると、機密設定データの暗号化を完全に制御できます。以下のセクションでは、カスタマーマネージドキーを使用するための要件、設定ステップ、およびアクセス許可について説明します。

### 要件
<a name="CloudWatch_Synthetics_function_encryption_requirements"></a>

カスタマーマネージドキーを設定する前に、次の要件を満たしているか確認してください。
+ AWS KMS キーは対称暗号化キーである必要があります。
+ キーポリシーは、発信者 (Synthetics API を呼び出す IAM プリンシパル) に `kms:CreateGrant` を付与するものでなければなりません。
+ AWS Lambda はその権限を使用して、保存中の環境変数の暗号化と復号化を行います。
+ AWS KMS キーは Canary と同じ AWS リージョンに存在している必要があります。

### カスタマーマネージドキーの設定
<a name="CloudWatch_Synthetics_function_encryption_configure"></a>

Canary の作成時や更新時にカスタマーマネージドキーを設定できます。次の手順は、Amazon CloudWatch コンソールと Synthetics API を使用して暗号化を設定する方法を示しています。

#### コンソールで暗号化を設定する
<a name="CloudWatch_Synthetics_function_encryption_configure_console"></a>

Amazon CloudWatch コンソールで Canary の作成や編集を行うには、**[環境変数]** セクションを展開します。**[保存時暗号化の設定]** で、**[カスタマーマネージドキーの使用]** を選択し、AWS KMS キーの ARN を選択または指定します。

#### API を使用して暗号化を設定する
<a name="CloudWatch_Synthetics_function_encryption_configure_api"></a>

`CreateCanary` または `UpdateCanary` を呼び出すときに、カスタマーマネージドキーの ARN を使用して `KmsKeyArn` パラメータを指定します。AWS マネージドキーに戻すには、`KmsKeyArn` に空の文字列を設定します。

#### 例: カスタマーマネージドキーを使用した CreateCanary リクエスト
<a name="CloudWatch_Synthetics_function_encryption_configure_example"></a>

```
{
"Name": "my-canary-EXAMPLE",
"KmsKeyArn": "arn:aws:kms:us-east-1:111122223333:key/a1b2c3d4-e5f6-7890-abcd-EXAMPLE11111",
"RunConfig": {
  "EnvironmentVariables": {
    "SECRET_KEY": "my-secret-value-EXAMPLE"
  }
}
}
```

### 保存時暗号化に必要なアクセス許可
<a name="CloudWatch_Synthetics_function_encryption_permissions"></a>

Canary の作成時や更新時には、AWS KMS キーに対する次のアクセス許可が必要です。
+ `kms:CreateGrant`, `kms:Encrypt`—Canary に対するカスタマーマネージドキーの設定に必要です。
+ `kms:Decrypt`—カスタマーマネージドキーで暗号化された環境変数の表示・管理に必要です。
+ `kms:DescribeKey`—そのキーの検証に必要です。

Canary 実行ロールには、保存時暗号化のための AWS KMS アクセス許可は不要です。Lambda はその権限を使用して暗号化と復号を処理します。

### マルチロケーション Canary
<a name="CloudWatch_Synthetics_function_encryption_multilocation"></a>

マルチロケーション Canary の場合、各レプリカロケーションに固有の AWS KMS キーを設けることができます。Canary の作成時や更新時に `AddReplicaLocations` パラメータで `KmsKeyArn` を指定します。このキーは、レプリカと同一のリージョン内に存在する必要があります。

## 転送中の環境変数の暗号化
<a name="CloudWatch_Synthetics_transit_encryption"></a>

保存時の暗号化に加えて、個々の環境変数値を CloudWatch Synthetics により保存される前に暗号化することができます。CloudWatch Synthetics では、これを「転送中の暗号化」と呼びます。転送中の値を暗号化すると、コンソールはプレーンテキストの値を、Canary のみがランタイム時に復号できる base64 でエンコードされた暗号文に置き換えます。

### 転送中の暗号化の仕組み
<a name="CloudWatch_Synthetics_transit_encryption_how"></a>

環境変数値に対して転送中の暗号化を選択した場合:

1. コンソールは、選択したAWS KMSキーで`kms:Encrypt`を呼び出して、プレーンテキスト値を暗号化します。

1. 環境変数設定のプレーンテキスト値が、暗号化された暗号文 (base64 エンコード) に置き換わります。

1. ランタイム時に、Canary スクリプトが `kms:Decrypt` を呼び出してその値を復号します。

### 転送中の暗号化に必要なアクセス許可
<a name="CloudWatch_Synthetics_transit_encryption_permissions"></a>

転送中の暗号化には、次のアクセス許可が必要です。
+ **コンソールユーザーまたは API 発信者** — AWS KMS キーの `kms:Encrypt`。値を保存する前に暗号化するには、このアクセス許可が必要です。
+ **Canary 実行ロール** — AWS KMS キーの `kms:Decrypt`。Canary の Lambda 関数では、ランタイム時に値を復号するためにこのアクセス許可が必要です。

以下は、Canary 実行ロールにアタッチする IAM ポリシーの例です。

```
{
"Version": "2012-10-17",
"Statement": [
  {
    "Effect": "Allow",
    "Action": "kms:Decrypt",
    "Resource": "arn:aws:kms:us-east-1:111122223333:key/a1b2c3d4-e5f6-7890-abcd-EXAMPLE11111"
  }
]
}
```

### Canary スクリプトでの値の復号化
<a name="CloudWatch_Synthetics_transit_encryption_decrypt"></a>

Canary スクリプトで暗号化された環境変数を使用するには、ランタイム時に復号します。次の Node.js の例は、環境変数の復号方法を示しています。

```
const { KMSClient, DecryptCommand } = require('@aws-sdk/client-kms');
const client = new KMSClient({ region: process.env.AWS_REGION });

async function decryptEnvVar(name) {
const encrypted = process.env[name];
const req = {
  CiphertextBlob: Buffer.from(encrypted, 'base64'),
};
const command = new DecryptCommand(req);
const response = await client.send(command);
return new TextDecoder().decode(response.Plaintext);
}

// Usage
const mySecret = await decryptEnvVar('MY_CONFIG_VAR');
```

## Canary と他の AWS のサービスとの統合
<a name="CloudWatch_Synthetics_Canaries_AWS_integrate"></a>

Canary の AWS SDK ライブラリを使用して、他の AWS サービスと統合することができます。

これを行うには、Canary に次のコードを追加します。これらの例では、Canary は AWS Secrets Manager と統合されています。
+ AWS SDK をインポートします。

  ```
  const AWS = require('aws-sdk');
  ```
+ 統合する AWS のサービスのクライアントを作成します。

  ```
  const secretsManager = new AWS.SecretsManager();
  ```
+ このクライアントを使用して、サービスへの API コールを行います。

  ```
  var params = {
  SecretId: secretName
  };
  return await secretsManager.getSecretValue(params).promise();
  ```

次の Canary スクリプトのコードスニペットは、Secrets Manager との統合方法をより詳細に示しています。

```
var synthetics = require('@aws/synthetics-puppeteer');
const log = require('@aws/synthetics-logger');

const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();

const getSecrets = async (secretName) => {
  var params = {
      SecretId: secretName
  };
  return await secretsManager.getSecretValue(params).promise();
}

const secretsExample = async function () {
  let URL = "<URL>";
  let page = await synthetics.getPage();

  log.info(`Navigating to URL: ${URL}`);
  const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000});

  // Fetch secrets
  let secrets = await getSecrets("secretname")

  /**
  * Use secrets to login.
  *
  * Assuming secrets are stored in a JSON format like:
  * {
  *   "username": "<USERNAME>",
  *   "password": "<PASSWORD>"
  * }
  **/
  let secretsObj = JSON.parse(secrets.SecretString);
  await synthetics.executeStep('login', async function () {
      await page.type(">USERNAME-INPUT-SELECTOR<", secretsObj.username);
      await page.type(">PASSWORD-INPUT-SELECTOR<", secretsObj.password);

      await Promise.all([
        page.waitForNavigation({ timeout: 30000 }),
        await page.click(">SUBMIT-BUTTON-SELECTOR<")
      ]);
  });

  // Verify login was successful
  await synthetics.executeStep('verify', async function () {
      await page.waitForXPath(">SELECTOR<", { timeout: 30000 });
  });
};

exports.handler = async () => {
  return await secretsExample();
};
```

## Canary に静的 IP アドレスの使用を強制する
<a name="CloudWatch_Synthetics_Canaries_staticIP"></a>

静的 IP アドレスを使用するように Canary を設定できます。

**Canary に静的 IP アドレスの使用を強制するには**

1. 新しい VPC を作成します。詳細については、「[Using DNS with Your VPC](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html)」を参照してください。

1. 新しいインターネットゲートウェイを作成します。詳細については、「[インターネットゲートウェイを VPC に追加する](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html#working-with-igw)」を参照してください。

1. 新しい VPC 内にパブリックサブネットを作成します。

1. 新しいルートテーブルを VPC に追加します。

1. `0.0.0.0/0` からインターネットゲートウェイに向かうルートを、新しいルートテーブルに追加します。

1. 新しいルートテーブルをパブリックサブネットに関連付けます。

1. Elastic IP アドレスを作成します。詳細については、「[Elastic IP アドレス](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html)」を参照してください。

1. 新しい NAT ゲートウェイを作成し、パブリックサブネットと Elastic IP アドレスに割り当てます。

1. VPC の内部にプライベートサブネットを作成します。

1. `0.0.0.0/0` から NAT ゲートウェイへのルートを VPC デフォルトルートテーブルに追加します。

1. Canary を作成します。