前言

IAM 全称 Identity and Access Management,中文翻译为身份和操控办理,是 AWS 供给的一项免费的权限操控服务。IAM 是云服务安全性的柱石,是开发者有必要把握的技术之一。试想如果一切资源都没有权限操控,任何人都能够随意修正和删除资源,这关于云端服务来说是一件多么危险的事情。

IAM 供给了多种权限操控计划,有根据用户的,也有根据人物的。这些计划都能完成权限操控的功能,因而初度接触 IAM 的开发者通常都会在计划挑选上堕入迷茫。

根据人物的权限操控是运用最广泛,也是最引荐的权限操控计划。本文的目标是使开发者能够快速了解并上手根据人物的权限操控。

概念

IAM 的权限操控包含三个维度(以下简称为三要素),即:

  1. 能(或不能)对
  2. 什么资源
  3. 做什么

例如:某 EC2 实例能够向某 S3 bucket 上传文件。这里的三要素别离是:

  1. 谁:某 EC2 实例
  2. 资源:某 S3 bucket
  3. 做什么:上传文件
flowchart LR
    subgraph 谁
        EC2
    end
    subgraph 资源
        S3[S3 bucket]
    end
    EC2 -->|上传| S3

谁(role)

在根据人物(role base)的权限操控中,人物便是三要素中的“”。一个人物能够被相关到多个委托人,一切被相关的委托人都会成为 IAM 三要素中“”。

flowchart LR
    subgraph principal[委托人]
        EC2
        ECS
        Lambda
    end
    subgraph role[人物]
        S3U["S3 上传者(role)"]
    end
    S3U --> EC2 & ECS & Lambda

人物“S3 上传者”被相关到了三个委托人(EC2,ECS,Lambda)。相关后,这三个委托人就都能够被看作是“S3 上传者”这个人物。

如果读者对人物和委托人的联系还不是很清楚,能够用 Java 中的类和接口来做一下类比。人物就像一个接口(interface),委托人便是完成了这个接口的类(class),这些类都能够被视为该接口。

interface SomeRole { }
class EC2 implements SomeRole { }
class ECS implements SomeRole { }
class Lambda implements SomeRole { }

资源(resource)

咱们能够赋予上述人物一些资源的权限,这些资源能够是任意一个 AWS 资源。例如某个 S3 bucket,某个数据库,某个音讯行列等。

做什么(action)

AWS 为每个资源都做了十分精细的权限操控。例如 S3 的权限包括:

  • s3:CreateBucket
  • s3:ListAllMyBuckets
  • s3:GetBucketLocation
  • s3:PutObject

这还仅仅冰山一角。到目前为止,S3 总共有上百个操控权限,概况能够看这里。

战略(policy)

IAM 把上述三要素组织在一个 json 文件中,并且给这个 json 起了个名字,叫做战略。例如:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::awsexamplebucket1/*"
        }
    ]
}
  • Version 是战略言语版别,最新版为 2012-10-17
  • Statement 是一系列三元素的调集,也便是说一个战略能够装备多个三元素操控权限。
  • Effect 的取值有 AllowDeny,别离表示答应或拒绝操作。示例中运用的是 Allow,表示答应 Action 中的操作。
  • Action 便是对资源(resource)的操作,是个数组,因而能够定义对某一资源的多个操作。
  • Resource 便是被操控的资源,示例中的是一个 S3 bucket。

战略与人物的联系

细心的读者会发现,资源(resource)和操作(action)已经体现在战略中了,可是似乎没有看到人物(role)的定义。其实人物和战略是两个独立的实体,经过将战略相关到人物来建立二者的联系。一个人物能够被相关多个战略。

如果把三元素和战略放在一起,他们会是如下的联系:

【AWS】IAM 系列(一)基于角色(role base)的权限控制

实战演练

把握了 IAM 三要素和战略之后,让咱们经过一个实战演练来展现一下根据人物的权限操控具体是怎么运用的。

在实战演练中,咱们会创立一个 Lambda,并经过人物赋予该 Lambda 读取一切 S3 bucket 的权限,如图所示:

【AWS】IAM 系列(一)基于角色(role base)的权限控制

创立 Lambda

咱们依然根据 CDK 来创立一切资源。运用 CDK 的好处是你无需手动去 AWS Console 做资源的创立和装备,仅需经过代码就可完成悉数操作。

初始化 CDK 项目

创立并进入一个项目文件夹。

mkdir iam-role-lambda
cd iam-role-lambda

初始化 CDK 项目。

cdk init app --language typescript

创立根据 Python 的 Lambda

用如下代码替换 ./lib/iam-role-lambda-stack.ts 中的内容。

import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class IamRoleLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    new lambda.Function(this, 'MyFunction', {
      runtime: lambda.Runtime.PYTHON_3_9,
      handler: 'app.lambda_handler',
      code: lambda.Code.fromAsset('./my_function'),
    });
  }
}

添加 Python 代码

创立 Python 代码文件。

mkdir my_function
cd my_function
touch app.py

将如下代码添加到 ./my_function/app.py 文件中。这是一段 Lambda 履行的 Python 代码,作用是罗列出我的 AWS 帐号中的一切 S3 bucket。

import boto3
def lambda_handler(event, context):
    # Retrieve the list of existing buckets
    s3 = boto3.client('s3')
    response = s3.list_buckets()
    # Output the bucket names
    print('Existing buckets:')
    for bucket in response['Buckets']:
        print(f'  {bucket["Name"]}')
    return "There are totally {} buckets.".format(len(response['Buckets']))

布置

现在就能够经过 CDK 将 Lambda 布置到云端了。

cdk deploy

你会看到相似如下输出:

✨  Synthesis time: 6.82s
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
IAM Statement Changes
┌───┬───────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│   │ Resource                      │ Effect │ Action         │ Principal                    │ Condition │
├───┼───────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${MyFunction/ServiceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:lambda.amazonaws.com │           │
└───┴───────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬───────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                  │ Managed Policy ARN                                                             │
├───┼───────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${MyFunction/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴───────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Do you wish to deploy these changes (y/n)? y
IamRoleLambdaStack: deploying...
[0%] start: Publishing f8f0b6e3c0970c2b86947588bc5ab7fe4031c3bd8ea32db737f41a96be64a01c:current_account-current_region
[0%] start: Publishing a7505bba7bbf4039cb047dabb3f44c5254c20fae6434b5b2ddbff30e7dfbb009:current_account-current_region
[50%] success: Published f8f0b6e3c0970c2b86947588bc5ab7fe4031c3bd8ea32db737f41a96be64a01c:current_account-current_region
[100%] success: Published a7505bba7bbf4039cb047dabb3f44c5254c20fae6434b5b2ddbff30e7dfbb009:current_account-current_region
IamRoleLambdaStack: creating CloudFormation changeset...
 ✅  IamRoleLambdaStack
✨  Deployment time: 58.14s
Stack ARN:
arn:aws:cloudformation:us-east-1:376200971131:stack/IamRoleLambdaStack/63a27650-e479-11ec-9052-12b9e23c7aa5
✨  Total time: 64.96s

现在翻开 AWS Console 网页,在 Lambda 页面的 Test 选项卡点击 Test 按钮履行该 Lambda。因为咱们还没有给 Lambda 赋予读取 S3 bucket 的权限,因而 Lambda 会抛出一个异常。

START RequestId: 6fd00bc4-2630-4cf4-ad2e-4b261142f943 Version: $LATEST
[ERROR] ClientError: An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
Traceback (most recent call last):
File "/var/task/app.py", line 6, in lambda_handler
response = s3.list_buckets()
File "/var/runtime/botocore/client.py", line 391, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/var/runtime/botocore/client.py", line 719, in _make_api_call
raise error_class(parsed_response, operation_name)END RequestId: 6fd00bc4-2630-4cf4-ad2e-4b261142f943
REPORT RequestId: 6fd00bc4-2630-4cf4-ad2e-4b261142f943	Duration: 1738.98 ms	Billed Duration: 1739 ms	Memory Size: 128 MB	Max Memory Used: 71 MB	Init Duration: 260.31 ms

创立人物并装备权限

为了让 Lambda 能够读取 S3 bucket,咱们需求创立一个人物,并为该人物装备答应访问 S3 bucket 的战略。修改 ./lib/iam-role-lambda-stack.ts 为如下内容:

import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
export class IamRoleLambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const myRole = new iam.Role(this, 'MyRole', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
    });
    myRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      resources: ['arn:aws:s3:::*'],
      actions: ['s3:ListAllMyBuckets'],
    }));
    new lambda.Function(this, 'MyFunction', {
      runtime: lambda.Runtime.PYTHON_3_9,
      handler: 'app.lambda_handler',
      code: lambda.Code.fromAsset('./my_function'),
      role: myRole,
    });
  }
}

在上边的代码中,咱们创立了一个名为 myRole 的人物,并且为该人物添加了一个战略。该战略答应对一切 S3 资源履行 s3:ListAllMyBuckets 操作。最后将该人物相关至 Lambda,使该 Lambda 具有相应权限。

再次履行 cdk deploy 布置,然后以同样的方法再次履行该 Lambda。这次 Lambda 成功读取了我的一切 S3 bucket,并在结果中返回了 bucket 的数量。

There are totally 57 buckets.

咱们的 Python 代码还在日志中记录了一切 S3 bucket 的名字。因为我的 bucket 数量过多,因而我只展现部分日志。

START RequestId: c3eb252b-246c-46c6-a715-ddc723c8d075 Version: $LATEST
Existing buckets:
cdk-hnb659fds-assets-376200971131-us-east-1
cdk-hnb659fds-assets-376200971131-us-west-2
...
END RequestId: c3eb252b-246c-46c6-a715-ddc723c8d075
REPORT RequestId: c3eb252b-246c-46c6-a715-ddc723c8d075	Duration: 1733.98 ms	Billed Duration: 1734 ms	Memory Size: 128 MB	Max Memory Used: 71 MB	Init Duration: 236.72 ms

总结

本文介绍了 IAM 三要素以及战略,并经过实战演练展现了怎么运用根据人物的权限操控赋予 Lambda 相关权限。不仅是 Lambda,AWS 中绝大多数的服务都能够经过人物装备权限,例如 ECS,Redshift 等。读者可重视各个服务中的人物选项自行装备。