View a markdown version of this page

常见的金丝雀功能 - Amazon CloudWatch

常见的金丝雀功能

您可以对所有金丝雀运行时使用下面的功能。

环境变量

您可以在创建金丝雀时使用环境变量。您可以编写单个金丝雀脚本,并将其与不同的值搭配使用来快速创建用于类似任务的多个金丝雀。

例如,假设贵组织具有用于不同软件开发阶段的端点(例如 proddevpre-release)。您必须创建金丝雀来测试每个端点。您可以编写一个金丝雀脚本来测试软件。然后,在创建三个金丝雀时,请分别指定不同的端点环境变量值。创建金丝雀时,请指定脚本和环境变量值。

环境变量的名称可以包含字母、数字和下划线字符,必须以字母开头,并且至少为两个字符。环境变量的总大小不能超过 4 KB。不能将任何 Lambda 预留环境变量指定为环境变量的名称。有关预留环境变量的更多信息,请参阅运行时环境变量

环境变量在客户端未加密

默认情况下,AWS 使用 AWS 自有密钥对环境变量键和值进行静态加密。但是,CloudWatch Synthetics 并不应用客户端加密。敏感信息在传输中加密后才能存储。有关更多信息,请参阅 对环境变量进行传输中加密。您还可以使用客户自主管理型 AWS KMS 密钥来对金丝雀的环境变量进行静态加密。有关更多信息,请参阅 使用客户自主管理型密钥对环境变量进行静态加密。

下面的示例脚本使用两个环境变量。此脚本用于检查网页是否可用的金丝雀。该金丝雀使用环境变量来参数化所检查的 URL 和所使用的 CloudWatch Synthetics 日志级别。

以下代码段是下面显示的完整脚本的一部分。

以下函数将 LogLevel 设置为 LOG_LEVEL 环境变量的值。

synthetics.setLogLevel(process.env.LOG_LEVEL);

此函数将 URL 设置为 URL 环境变量的值。

const URL = process.env.URL;

下面的完整脚本演示了这两个环境变量。当您使用此脚本创建金丝雀时,您可以指定 LOG_LEVELURL 环境变量的值。

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(); };

将环境变量传递到脚本

要在控制台中创建金丝雀时将环境变量传递给脚本,请在控制台上的 Environment variables(环境变量)部分指定环境变量的密钥和值。有关更多信息,请参阅 创建金丝雀

要通过 API 或 AWS CLI 传递环境变量,请使用 RunConfig 部分中的 EnvironmentVariables 参数。以下为 AWS CLI 命令示例,该命令创建一个使用两个环境变量(具有 EnvironmentRegion 密钥)的金丝雀。

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" }'

使用客户自主管理型密钥对环境变量进行静态加密。

默认情况下,AWS 自有密钥会对金丝雀环境变量进行静态加密。您可以指定客户自主管理型 AWS KMS 密钥来对金丝雀环境变量进行静态加密。使用客户自主管理型密钥,您可以完全控制敏感配置数据的加密。以下部分介绍使用客户自主管理型的要求、配置步骤和权限。

要求

配置客户自主管理型密钥之前,请确认您满足以下要求:

  • AWS KMS 密钥必须是对称加密密钥。

  • 密钥策略必须向调用方(调用 Synthetics API 的 IAM 主体)授予 kms:CreateGrant

  • AWS Lambda 使用该授权对环境变量进行静态加密和解密。

  • AWS KMS 密钥必须与金丝雀版本位于同一 AWS 区域。

配置客户自主管理型密钥

您可以在创建或更新金丝雀时配置客户自主管理型密钥。以下过程展示了如何使用 Amazon CloudWatch 控制台和 Synthetics API 来配置加密。

在控制台中配置加密

要在 Amazon CloudWatch 控制台中创建或编辑金丝雀,请展开环境变量部分。在静态加密配置下,选择使用客户自主管理型密钥,然后选择或指定 AWS KMS 密钥的 ARN。

使用 API 配置加密

调用 CreateCanaryUpdateCanary 时,请使用客户自主管理型密钥的 ARN 指定 KmsKeyArn 参数。要恢复为 AWS 托管式密钥,请将 KmsKeyArn 设置为空字符串。

示例:使用客户自主管理型密钥创建金丝雀请求

{ "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" } } }

静态加密所需的权限

如果创建或更新金丝雀,则必须对 AWS KMS 密钥具有以下权限:

  • kms:CreateGrantkms:Encrypt:为金丝雀配置客户自主管理型密钥所必需的。

  • kms:Decrypt:查看和管理使用客户自主管理型密钥加密的环境变量所必需的。

  • kms:DescribeKey:验证密钥所必需的。

金丝雀执行角色不需要任何 AWS KMS 权限即可进行静态加密。Lambda 使用该授权来处理加密和解密。

多位置金丝雀

对于多位置金丝雀,每个副本位置都可以拥有自己的 AWS KMS 密钥。创建或更新金丝雀时,请在 AddReplicaLocations 参数中指定 KmsKeyArn。密钥必须与副本位于同一区域。

对环境变量进行传输中加密

除了静态加密之外,您还可以在 CloudWatch Synthetics 存储各个环境变量值之前对其进行加密。CloudWatch Synthetics 称之为传输中加密。当对值进行传输中加密时,控制台会将明文值替换为 base64 编码的加密文字,仅您的金丝雀可以在运行时解密该加密文字。

传输中加密的工作原理

当您选择对环境变量值进行传输中加密时:

  1. 控制台使用您选择的 AWS KMS 密钥调用 kms:Encrypt 以加密明文值。

  2. 加密的加密文字(base64 编码)取代了环境变量配置中的明文值。

  3. 在运行时,金丝雀脚本会通过调用 kms:Decrypt 来解密该值。

传输中加密所需的权限

您需要拥有以下权限才能进行传输中加密:

  • 控制台用户或 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" } ] }

解密金丝雀脚本中的值

要在金丝雀脚本中使用经过加密的环境变量,请在运行时对其进行解密。以下 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 服务集成

您可以在金丝雀中使用 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(); };

强制金丝雀使用静态 IP 地址

您可以设置金丝雀,使其使用静态 IP 地址。

强制金丝雀使用静态 IP 地址
  1. 创建新的 VPC。有关更多信息,请参阅将 DNS 与您的 VPC 一起使用

  2. 创建新的互联网网关。有关更多信息,请参阅在您的 VPC 中添加互联网网关

  3. 在新的 VPC 内创建公有子网。

  4. 向 VPC 添加新的路由表。

  5. 在新路由表中添加一条从 0.0.0.0/0 到互联网网关的路由。

  6. 将新的路由表与公有子网关联。

  7. 创建弹性 IP 地址。有关更多信息,请参阅弹性 IP 地址

  8. 创建一个新的 NAT 网关,并将其分配给公有子网和弹性 IP 地址。

  9. 在 VPC 中创建私有子网。

  10. 向 VPC 默认路由表添加一条从 0.0.0.0/0 到 NAT 网关的路由。

  11. 创建金丝雀。