

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在 Guard 规则中分配和引用变量
<a name="variables"></a>

您可以在 AWS CloudFormation Guard 规则文件中分配变量，以存储要在 Guard 规则中引用的信息。Guard 支持一次性变量赋值。变量是延迟计算的，这意味着 Guard 仅在规则运行时才计算变量。

**Topics**
+ [分配变量](#assigning-variables)
+ [引用变量](#referencing-variables)
+ [变量作用域](#variable-scope)
+ [守卫规则文件中的变量示例](#variables-examples)

## 分配变量
<a name="assigning-variables"></a>

使用`let`关键字初始化变量并分配变量。最佳做法是使用蛇形大小写变量名。变量可以存储查询产生的静态文字或动态属性。在以下示例中，变量`ecs_task_definition_task_role_arn`存储静态字符串值`arn:aws:iam:123456789012:role/my-role-name`。

```
let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-role-name'
```

在以下示例中，变量`ecs_tasks`存储了在 CloudFormation 模板中搜索所有`AWS::ECS::TaskDefinition`资源的查询结果。在编写规则时`ecs_tasks`，您可以参考有关这些资源的访问信息。

```
let ecs_tasks = Resources.*[
    Type == 'AWS::ECS::TaskDefinition'
]
```

## 引用变量
<a name="referencing-variables"></a>

使用前`%`缀来引用变量。

根据中的`ecs_task_definition_task_role_arn`变量示例[分配变量](#assigning-variables)，您可以在 Guard 规则子句的`query|value literal`部分`ecs_task_definition_task_role_arn`中进行引用。使用该引用可确保为 CloudFormation 模板中任何`AWS::ECS::TaskDefinition`资源的`TaskDefinitionArn`属性指定的值都是静态字符串值`arn:aws:iam:123456789012:role/my-role-name`。

```
Resources.*.Properties.TaskDefinitionArn == %ecs_task_definition_role_arn
```

根据中的`ecs_tasks`变量示例[分配变量](#assigning-variables)，您可以在查询中进行引用`ecs_tasks`（例如，%ecs\$1tasks.Properties）。首先，Guard 评估变量，`ecs_tasks`然后使用返回的值遍历层次结构。如果变量`ecs_tasks`解析为非字符串值，则 Guard 会引发错误。

**注意**  
目前，Guard 不支持在自定义错误消息中引用变量。

## 变量作用域
<a name="variable-scope"></a>

范围是指规则文件中定义的变量的可见性。一个变量名只能在一个作用域内使用一次。有三个级别可以声明变量，或者有三个可能的变量范围：
+ **文件级** — 通常在规则文件顶部声明，可以在规则文件的所有规则中使用文件级变量。它们对整个文件都是可见的。

  在以下示例规则文件中，变量`ecs_task_definition_task_role_arn`和`ecs_task_definition_execution_role_arn`是在文件级别初始化的。

  ```
  let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-task-role-name'
  let ecs_task_definition_execution_role_arn = 'arn:aws:iam::123456789012:role/my-execution-role-name'
  
  rule check_ecs_task_definition_task_role_arn
  {
      Resources.*.Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
  }
  
  rule check_ecs_task_definition_execution_role_arn
  {
      Resources.*.Properties.ExecutionRoleArn == %ecs_task_definition_execution_role_arn
  }
  ```
+ **规则级别** — 在规则中声明，规则级变量仅对该特定规则可见。规则之外的任何引用都会导致错误。

  在以下示例规则文件中，变量`ecs_task_definition_task_role_arn`和`ecs_task_definition_execution_role_arn`是在规则级别初始化的。`ecs_task_definition_task_role_arn`只能在`check_ecs_task_definition_task_role_arn`命名规则中引用。您只能在`check_ecs_task_definition_execution_role_arn`命名规则中引用该`ecs_task_definition_execution_role_arn`变量。

  ```
  rule check_ecs_task_definition_task_role_arn
  {
      let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-task-role-name'
      Resources.*.Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
  }
  
  rule check_ecs_task_definition_execution_role_arn
  {
      let ecs_task_definition_execution_role_arn = 'arn:aws:iam::123456789012:role/my-execution-role-name'
      Resources.*.Properties.ExecutionRoleArn == %ecs_task_definition_execution_role_arn
  }
  ```
+ **块级** — 在块（例如`when`子句）中声明，块级变量仅对该特定块可见。区块之外的任何引用都会导致错误。

  在以下示例规则文件中，变量`ecs_task_definition_task_role_arn`和`ecs_task_definition_execution_role_arn`是在类型块内的块级别初始化的`AWS::ECS::TaskDefinition`。您只能在`AWS::ECS::TaskDefinition`类型块中为其各自的规则引用`ecs_task_definition_task_role_arn`和`ecs_task_definition_execution_role_arn`变量。

  ```
  rule check_ecs_task_definition_task_role_arn
  {
      AWS::ECS::TaskDefinition
      {
          let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-task-role-name'
          Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
      }
  }
  
  rule check_ecs_task_definition_execution_role_arn
  {
      AWS::ECS::TaskDefinition
      {
          let ecs_task_definition_execution_role_arn = 'arn:aws:iam::123456789012:role/my-execution-role-name'
          Properties.ExecutionRoleArn == %ecs_task_definition_execution_role_arn
      }
  }
  ```

## 守卫规则文件中的变量示例
<a name="variables-examples"></a>

以下各节提供了变量静态和动态赋值的示例。

### 静态赋值
<a name="assigning-static-variables"></a>

以下是一个示例 CloudFormation 模板。

```
Resources:
  EcsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      TaskRoleArn: 'arn:aws:iam::123456789012:role/my-role-name'
```

基于此模板，您可以编写一个名为的规则，该规则可`check_ecs_task_definition_task_role_arn`确保所有`AWS::ECS::TaskDefinition`模板资源的`TaskRoleArn`属性均为`arn:aws:iam::123456789012:role/my-role-name`。

```
rule check_ecs_task_definition_task_role_arn
{
    let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-role-name'
    Resources.*.Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
}
```

在规则的范围内，您可以初始化名`ecs_task_definition_task_role_arn`为的变量，并为其分配静态字符串值`'arn:aws:iam::123456789012:role/my-role-name'`。规则子句`arn:aws:iam::123456789012:role/my-role-name`通过引用`query|value literal`部分中的`ecs_task_definition_task_role_arn`变量来检查为`EcsTask`资源`TaskRoleArn`属性指定的值是否为该值。

### 动态分配
<a name="example-dynamic-assignment"></a>

以下是一个示例 CloudFormation 模板。

```
Resources:
  EcsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      TaskRoleArn: 'arn:aws:iam::123456789012:role/my-role-name'
```

基于此模板，您可以初始化在文件`ecs_tasks`范围内调用的变量，并将查询分配给该变量`Resources.*[ Type == 'AWS::ECS::TaskDefinition'`。Guard 会查询输入模板中的所有资源，并将有关这些资源的信息`ecs_tasks`。你也可以编写一个名为的规则，`check_ecs_task_definition_task_role_arn`确保所有`AWS::ECS::TaskDefinition`模板资源的`TaskRoleArn`属性都是 `arn:aws:iam::123456789012:role/my-role-name`

```
let ecs_tasks = Resources.*[
    Type == 'AWS::ECS::TaskDefinition'
]

rule check_ecs_task_definition_task_role_arn
{
    %ecs_tasks.Properties.TaskRoleArn == 'arn:aws:iam::123456789012:role/my-role-name'
}
```

规则子句`arn:aws:iam::123456789012:role/my-role-name`通过引用`query`部分中的`ecs_task_definition_task_role_arn`变量来检查为`EcsTask`资源`TaskRoleArn`属性指定的值是否为该值。

### 强制 CloudFormation 模板配置
<a name="example-3"></a>

让我们来看一个更复杂的生产用例示例。在此示例中，我们编写了防护规则，以确保更严格地控制 Amazon ECS 任务的定义方式。

以下是一个示例 CloudFormation 模板。

```
Resources:
  EcsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      TaskRoleArn: 
        'Fn::GetAtt': [TaskIamRole, Arn]
      ExecutionRoleArn:
        'Fn::GetAtt': [ExecutionIamRole, Arn]

  TaskIamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      PermissionsBoundary: 'arn:aws:iam::123456789012:policy/MyExamplePolicy'

  ExecutionIamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      PermissionsBoundary: 'arn:aws:iam::123456789012:policy/MyExamplePolicy'
```

基于此模板，我们编写了以下规则来确保满足这些要求：
+ 模板中的每个`AWS::ECS::TaskDefinition`资源都附加了一个任务角色和一个执行角色。
+ 任务角色和执行角色是 AWS Identity and Access Management (IAM) 角色。
+ 角色在模板中定义。
+ 该`PermissionsBoundary`属性是为每个角色指定的。

```
# Select all Amazon ECS task definition resources from the template
let ecs_tasks = Resources.*[
    Type == 'AWS::ECS::TaskDefinition'
]

# Select a subset of task definitions whose specified value for the TaskRoleArn property is an Fn::Gett-retrievable attribute
let task_role_refs = some %ecs_tasks.Properties.TaskRoleArn.'Fn::GetAtt'[0]

# Select a subset of TaskDefinitions whose specified value for the ExecutionRoleArn property is an Fn::Gett-retrievable attribute
let execution_role_refs = some %ecs_tasks.Properties.ExecutionRoleArn.'Fn::GetAtt'[0]

# Verify requirement #1
rule all_ecs_tasks_must_have_task_end_execution_roles 
    when %ecs_tasks !empty 
{
    %ecs_tasks.Properties {
        TaskRoleArn exists
        ExecutionRoleArn exists
    }
}

# Verify requirements #2 and #3
rule all_roles_are_local_and_type_IAM
    when all_ecs_tasks_must_have_task_end_execution_roles
{
    let task_iam_references = Resources.%task_role_refs
    let execution_iam_reference = Resources.%execution_role_refs

    when %task_iam_references !empty {
        %task_iam_references.Type == 'AWS::IAM::Role'
    }

    when %execution_iam_reference !empty {
        %execution_iam_reference.Type == 'AWS::IAM::Role'
    }
}

# Verify requirement #4
rule check_role_have_permissions_boundary
    when all_ecs_tasks_must_have_task_end_execution_roles
{
    let task_iam_references = Resources.%task_role_refs
    let execution_iam_reference = Resources.%execution_role_refs

    when %task_iam_references !empty {
        %task_iam_references.Properties.PermissionsBoundary exists
    }

    when %execution_iam_reference !empty {
        %execution_iam_reference.Properties.PermissionsBoundary exists
    }
}
```