服务
关于
CloudProse博客
安全和IAM

加强'Two-Person Rule'使用AWS 代码管道

您的CI / CD管道中是否有手动审批门?让'查看AWS 代码管道是否可以自动化。
福雷斯特Brazeal Trek10 191210 171202
阿甘(Forrest Brazeal) | 2018年3月5日
3分钟阅读

更新3/23/2018 AWS 代码管道团队已更新其 文件资料 表示实际上可以对批准使用IAM资源级别的权限。我更新了下面的信息,以解释其工作原理以及其余的陷阱。

今天您可能还活着,这要归功于”两人法则”-美国的军事政策要求发射两枚钥匙才能发射核导弹,因此一名疯狂的军官无法发起第三次世界大战。

也许您公司的软件并不像核弹头那么危险,但是您仍然希望它不会炸毁您的脸。因此,您可能选择将某种形式的两人规则集成为CI / CD管道的一部分:要求多个人在代码更改进入生产环境之前手动注销。

我最近一直在和 代码管道,这是一项AWS服务,可在云中自动执行代码构建和部署。当我看到CodePipeline支持 手动批准动作,我想:“将两个人的规则作为流水线阶段的一部分来实施会有多难?”

在AWS 代码管道中实施多个批准人

由于我们正在使用 我是 对于我们的AWS环境中的用户进行身份验证,两人批准解决方案应满足以下条件:

  • 在成功退出管道阶段之前,CodePipeline必须记录两个或多个手动批准
  • 每个批准都必须与有效的IAM用户或角色相关联
  • 批准者必须不同:同一IAM负责人不能为同一管道阶段的执行提供多个批准

基于IAM的批准

进行此设置的最合乎逻辑的方法是在管道阶段结束时并行放置两个批准操作,如下所示:

然后,您可以创建两个IAM角色或组,并为每个组授予仅批准两个批准操作之一的权限。现在,您可以将管理用户划分为两个组,您就可以开始了。

不幸, AWS 代码管道 当前不支持资源级权限 针对“ PutApprovalResult” 我是 操作. 代码管道 确实支持!诀窍是IAM视觉政策编辑器不知道这一点,并且会向您显示一条警告,指出不支持资源级权限。要设置资源级权限,您需要在JSON编辑器中定义两个IAM策略,如下所示:

A组批准政策

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "codepipeline:PutApprovalResult",
            "Resource": "arn:aws:codepipeline:[region]:[account]:*/*/ApprovalA",
            "Effect": "Allow"
        }
    ]
}

B组批准政策

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "codepipeline:PutApprovalResult",
            "Resource": "arn:aws:codepipeline:[region]:[account]:*/*/ApprovalB",
            "Effect": "Allow"
        }
    ]
}

You can attach these policies to two different 我是 groups or roles, and divide your 我是 users between those groups. As long as an individual user belongs to a maximum of one approval group, and you keep a consistent naming scheme (in this case, ApprovalA and ApprovalB) for your pipeline approval actions, then any user in the A group who tries to approve a B action, or vice versa, should see this error message:

繁荣!两人规则已经生效,只需要几行JSON。不错!

Lambda批准检查

上述方法的唯一问题是,它取决于您的IAM管理员,请确保没有单个IAM用户有权在管道阶段批准两个操作,并且您的操作名称在所有管道中都一致。如果我们可以通过某种方式在管道本身中以编程方式强制执行不同的批准者,那岂不是很好吗?

你看 - AWS使您可以将Lambda函数连接到CodePipeline阶段。此功能通常用于部署代码或运行测试,但是没有什么阻止我们编写对管道本身状态进行内部检查的函数。

本质上,我们只想确保两个不同的IAM实体执行了我们的两个批准操作,如果它们不匹配,则会抛出错误。这是使用GetPipelineStage API调用进行的相对容易的检查,如下面的示例Python Lambda函数所示:

from __future__ import print_function
import boto3
import traceback

code_pipeline = boto3.client('codepipeline')

def put_job_success(job, message):
    code_pipeline.put_job_success_result(jobId=job)
  
def put_job_failure(job, message):
    code_pipeline.put_job_failure_result(jobId=job, failureDetails={'message': message, 'type': 'JobFailed'})

def lambda_handler(event, context):
    try:
        job_id = event['CodePipeline.job']['id']
        state = code_pipeline.get_pipeline_state(name='YOUR_PIPELINE_NAME_HERE')
        stage = state['stageStates'][1]
        first_approver = stage['actionStates'][0]['latestExecution']['lastUpdatedBy']
        second_approver = stage['actionStates'][1]['latestExecution']['lastUpdatedBy']

        if first_approver == second_approver:
            put_job_failure(job_id, "ERROR: This pipeline does not permit the same approver ({}) to provide two approvals!".format(first_approver))
        else:
            put_job_success(job_id, "Two different approvers signed off on this change: {} , {}".format(first_approver, second_approver))


    except Exception as e:
        # If any other exceptions which we didn't expect are raised
        # then fail the job and log the exception message.
        traceback.print_exc()
        put_job_failure(job_id, 'Function exception: ' + str(e))
        
    return

注意

仅保证上述示例实现在IAM用户之间强制执行唯一批准。您可能需要进行一些管理方面的工作,才能确保具有批准CodePipeline执行权限的角色与不同的用户组相关联。您还必须考虑会话-您不希望用户使用不同的会话名称两次承担相同的角色,并且让您的代码将其识别为两个不同的角色。这些注意事项留给读者练习。 :)

现在,我们可以将此功能链接到我们的管道中。只要批准者不同,管道就会成功,如下所示:

如果同一用户尝试批准两个手动操作,则管道执行将失败,并显示如下错误:

其他限制

现在,我们有了一个可以实现我们主要目标的解决方案:停止执行CodePipeline,除非它得到两个不同身份的手动批准。但是,它仍然不是理想的解决方案。仅仅因为有人试图批准两个动作而使整个管道执行失败,这有点太激烈了-毕竟,特别是如果您要整理一堆CodeBuild作业时,运行CodePipeline可能会花费很多时间。如果我们只是拒绝第二次批准尝试,并让该批准操作公开以供另一位授权人员进行审核,这会好得多,这实际上是暂停执行,而不是直接使执行失败。

代码管道 确实支持API调用 重试特定阶段,但到目前为止,它仅重试 失败了 在那个阶段的行动。从流水线执行的后期开始,没有办法将“成功”动作任意标记为失败,反之亦然,这可能是一件好事,但这确实意味着我们无法使用Lambda函数来回退并将第二个批准操作标记为失败,以便我们重试。

但是现在我们只是挑剔。最终,结合使用基于IAM的批准和Lambda健全性检查,应该可以使您牢固而安全地实施两人规则。您的生产环境可以松一口气-世界末日已经避免!

作者
福雷斯特Brazeal Trek10 191210 171202
阿甘(Forrest Brazeal)