

# 일반적인 카나리 기능
<a name="CloudWatch_Synthetics_Canaries_CommonFeatures"></a>

모든 카나리 런타임에서 다음 기능을 사용할 수 있습니다.

## 환경 변수
<a name="CloudWatch_Synthetics_Environment_Variables"></a>

카나리를 생성할 때 환경 변수를 사용할 수 있습니다. 단일 카나리 스크립트를 작성하고 다른 값으로 사용하여 유사한 태스크에 대해 여러 카나리를 빠르게 생성할 수 있습니다.

예를 들어 조직에 다양한 소프트웨어 개발 단계에 대한 `prod`, `dev` 및 `pre-release`와 같은 엔드포인트가 있다고 가정해 보겠습니다. 각 엔드포인트를 테스트하려면 카나리를 생성해야 합니다. 소프트웨어를 테스트하는 단일 카나리 스크립트를 작성할 수 있습니다. 그런 다음 3개의 카나리를 각각 생성할 때 서로 다른 엔드포인트 환경 변수 값을 지정합니다. 카나리를 생성할 때 스크립트 및 환경 변수 값을 지정합니다.

환경 변수의 이름에는 문자, 숫자, 밑줄 문자가 포함될 수 있습니다. 이름은 문자로 시작해야 하며 2자 이상이어야 합니다. 환경 변수의 총 크기는 4KB를 초과할 수 없습니다. 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 키를 사용하여 카나리의 유휴 환경 변수를 암호화할 수도 있습니다. 자세한 내용은 [고객 관리형 키로 저장 시 환경 변수 암호화](#CloudWatch_Synthetics_function_encryption) 섹션을 참조하세요.

다음 스크립트 예에서는 두 개의 환경 변수를 사용합니다. 이 스크립트는 웹 페이지를 사용할 수 있는지 여부를 확인하는 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` 키가 있는 두 개의 환경 변수를 사용하는 canary를 생성하는 AWS CLI 명령의 예입니다.

`EnvironmentVariables`를 포함한 `RunConfig` 파라미터의 전체 스키마는 *Amazon CloudWatch Synthetics API 참조*의 [CanaryRunConfigInput](https://docs.aws.amazon.com/AmazonSynthetics/latest/APIReference/API_CanaryRunConfigInput.html)을 참조하세요.

```
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 소유 키는 유휴 시 카나리 환경 변수를 암호화합니다. 고객 관리형 AWS KMS 키를 지정하여 유휴 시 카나리 환경 변수를 암호화할 수 있습니다. 고객 관리형 키를 사용하면 민감한 구성 데이터의 암호화를 완벽하게 제어할 수 있습니다. 다음 섹션에서는 고객 관리형 키를 사용하기 위한 요구 사항, 구성 단계 및 권한을 설명합니다.

### 요구 사항
<a name="CloudWatch_Synthetics_function_encryption_requirements"></a>

고객 관리형 키를 구성하기 전에 다음 요구 사항을 충족하는지 확인합니다.
+ AWS KMS 키는 대칭 암호화 키여야 합니다.
+ 키 정책은 호출자(Synthetics API를 직접적으로 호출하는 IAM 위탁자)에게 `kms:CreateGrant`를 부여해야 합니다.
+ AWS Lambda는 권한 부여를 사용하여 유휴 환경 변수를 암호화하고 복호화합니다.
+ AWS KMS 키는 카나리와 동일한 AWS 리전에 있어야 합니다.

### 고객 관리형 키 구성
<a name="CloudWatch_Synthetics_function_encryption_configure"></a>

카나리를 생성하거나 업데이트할 때 고객 관리형 키를 구성할 수 있습니다. 다음 절차에서는 Amazon CloudWatch 콘솔과 Synthetics API를 사용하여 암호화를 구성하는 방법을 보여줍니다.

#### 콘솔에서 암호화 구성
<a name="CloudWatch_Synthetics_function_encryption_configure_console"></a>

Amazon CloudWatch 콘솔에서 카나리를 생성하거나 편집하려면 **환경 변수** 섹션을 확장합니다. **저장 시 암호화 구성**에서 **고객 관리형 키 사용**을 선택한 다음 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>

카나리를 생성하거나 업데이트하는 경우 AWS KMS 키에 대해 다음 권한이 있어야 합니다.
+ `kms:CreateGrant`, `kms:Encrypt`- 카나리에 대한 고객 관리형 키를 구성하는 데 필요합니다.
+ `kms:Decrypt` – 고객 관리형 키로 암호화된 환경 변수를 보고 관리하는 데 필요합니다.
+ `kms:DescribeKey`- 키를 검증하는 데 필요합니다.

카나리 실행 역할에는 저장 시 암호화를 위한 AWS KMS 권한이 필요하지 않습니다. Lambda는 권한 부여를 사용하여 암호화와 복호화를 처리합니다.

### 다중 위치 카나리
<a name="CloudWatch_Synthetics_function_encryption_multilocation"></a>

다중 위치 카나리의 경우 각 복제본 위치에 자체 AWS KMS 키가 있을 수 있습니다. 카나리를 생성하거나 업데이트할 때 `AddReplicaLocations` 파라미터에서 `KmsKeyArn`을 지정합니다. 키가 복제본과 동일한 리전에 있어야 합니다.

## 전송 중 환경 변수 암호화
<a name="CloudWatch_Synthetics_transit_encryption"></a>

저장 시 암호화 외에도 CloudWatch Synthetics가 저장하기 전에 개별 환경 변수 값을 암호화할 수 있습니다. CloudWatch Synthetics는 이를 전송 중 암호화라고 합니다. 전송 중 값을 암호화하면 콘솔은 일반 텍스트 값을 카나리만 런타임에 복호화할 수 있는 base64로 인코딩된 사이퍼텍스트로 바꿉니다.

### 전송 중 암호화 작동 방식
<a name="CloudWatch_Synthetics_transit_encryption_how"></a>

전송 중 환경 변수 값을 암호화하도록 선택하는 경우

1. 콘솔은 선택한 AWS KMS 키로 `kms:Encrypt`를 직접적으로 호출하여 일반 텍스트 값을 암호화합니다.

1. 암호화된 사이퍼텍스트(base64 인코딩)는 환경 변수 구성의 일반 텍스트 값을 대체합니다.

1. 런타임 시 카나리 스크립트는 `kms:Decrypt`를 직접적으로 호출하여 값을 복호화합니다.

### 전송 중 암호화에 필요한 권한
<a name="CloudWatch_Synthetics_transit_encryption_permissions"></a>

전송 중 암호화에는 다음 권한이 필요합니다.
+ **콘솔 사용자 또는 API 호출자** - AWS KMS 키에 대한 `kms:Encrypt`입니다. 값을 저장하기 전에 암호화하려면 이 권한이 필요합니다.
+ **카나리아 실행 역할** - AWS KMS 키에 대한 `kms:Decrypt`입니다. 카나리의 Lambda 함수는 런타임 시 값을 복호화하려면 이 권한이 필요합니다.

다음은 카나리 실행 역할에 연결할 예제 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"
    }
  ]
}
```

### 카나리 스크립트의 값 복호화
<a name="CloudWatch_Synthetics_transit_encryption_decrypt"></a>

카나리 스크립트에서 암호화된 환경 변수를 사용하려면 런타임에 복호화합니다. 다음 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');
```

## 다른 AWS 서비스와 canary 통합
<a name="CloudWatch_Synthetics_Canaries_AWS_integrate"></a>

카나리의 AWS SDK 라이브러리를 사용하여 다른 AWS 서비스와 통합할 수 있습니다.

이렇게 하려면 카나리에 다음 코드를 추가합니다. 이 예제에서 카나리는 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();
  ```

다음 카나리 스크립트 코드 스니펫은 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>

canary가 고정 IP 주소를 사용하도록 canary를 설정할 수 있습니다.

**canary가 고정 IP 주소를 사용하도록 지정하려면**

1. 새 VPC를 생성합니다. 자세한 내용은 [VPC에서 DNS 사용하기](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. 탄력적 IP 주소를 생성합니다. 자세한 내용은 [탄력적인 IP 주소](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) 섹션을 참조하십시오.

1. 새 NAT 게이트웨이를 생성하여 퍼블릭 서브넷 및 탄력적 IP 주소에 할당합니다.

1. VPC 내부에 프라이빗 서브넷을 생성합니다.

1. `0.0.0.0/0`에서 NAT 게이트웨이로 이동하는 경로를 VPC 기본 라우팅 테이블에 추가합니다.

1. canary를 생성합니다.