Pensieve: 2011

2020-11-24 08:21

所观所读所听

Netflix上看完了齐木楠雄的灾难/重启, 不用动脑筋的泡面番, 早饭时无聊看正好.

电影看了八佰, 看完后去翻历史, 对比战损比, 觉得像这个导演这么拍有点戏说的味道了. 后面教娃唱Auld Lang Syne的时候想起无间道2, 于是在Netflix上找来重看了一遍, 众生皆苦.

读书来说, 主要时间花在了考试的准备上, 所以除了月初看完1984后没开新坑了. 准备的过程中看了下面这两本:

实话说, 我觉得两本书都比较水, 比较简单. 现在考完试, 准备开工百年孤独.

音乐方面, 这个月听得比较多的是Alessia Tondo唱的Nuvole Bianche. 我琢磨着同样是意大利语, 唱歌剧的时候为什么就没有这样动听呢? 另外一个偶然发现是Betsy Phillips & Robby Hecht合作唱的Auld Lang Syne, 我觉得挺好听.

Security Jam

这个是AWS组织的一个免费活动, 随机几个人组队, 做一些安全方面的题目, 然后看哪个小队的得分比较高. 疫情当下, 这个本应该在线下举办的活动改到了线上, 线上活动就暴露出短板来了: 和线下活动相比, 现在没有任何约束逼迫你完成这个比赛, 所以参与度很低. 我理应和另外四个人组队完成挑战, 最后在解题的只有我一个人, 这一点让我很不爽. 部分题目本身也比较有误导性, 让人有点无奈. 不过从一个AWS从业人员的角度出发, 我也不由得赞赏AWS在这个上面所花费的努力, 首先你要了解哪些地方是经常出错的, 然后你要设计出一个应用场景让人来填空/改错, 最后, 你要合理实现这样的设计, 同时避免解题者用各种手段绕过你设下的限制(即你的系统本身需要是安全的).

上手第一题比较简单, 一个S3的网站被人改了, 想改回来. 上去之后发现这个S3开了版本支持, 于是就很容易解决了. 第二题是一个自动创建VPC Flowlog的lambda要补全lambda的iam权限, 这个题卡了我很久, 也是因为之前没用lambda启用过Flowlog, 实际上最后除了普通权限外还需要一个iam:PassRole. 恶心的是, 这个题是要求你写最小权限, 但是就我理解, 除了给最小权限的Action外, 通过添加Condition的方式做更严格的限制也是对最小权限的具体化, 所以我花了不少时间在尝试写各种Condition上. 后面还有一题是如何iam提权, 这个类黑客的题对于我而言就相对简单了: 一个账户里面有普通用户和管理员用户, 管理员用户登录后可以assume-role到另外一个role去执行某些操作. 普通用户登录后不能assume-role, 但是有iam修改的权限, 我当时直接当一个chain assume-role, 在cli中依次assume-role后拿管理员的Role当跳板最后拿到了目标role, 后来回头想想自己没必要这样搞, 直接改目标role的信任关系就可以了. 后面还有一题是一个标准的kms policy + iam policy + s3 bucket policy混合调试的题目, 不过题目本身说当执行完某些操作后, 另一个AWS账户里的一个lambda会拿到解密结果, 你可以调用某个apigw的接口拿到结果. 我当时调试了很久没调出来, 后来发现是忽视了一些policy的写法. 而且这个跨账号拿结果的方式也很幺蛾子, 不如直接告诉我们写对了策略直接解密一个文件就能拿到结果. 最后一个是纯操作类的题目, 按照一步步的指引, 写一个security hub的custom action出来, 不赘.

做完这些题目后, 我最大的感受是平常用多了高权限用户后, 要调试东西都不知道怎么调试了, 这也是我对这个解题的模式有点不满的原因, 一个正常的环境中, 即使我们没有权限, 我们也可以通过和同事沟通一起去看是什么情况, 不会真的像这样面对一个纯黑盒.

iSH

花了一点点时间在iSH上, 安装完app后装apk也没什么问题, 然后创建用户装基本cli环境也没问题, 甚至我把我的etc直接拿过来都没有特别多的报错, 而且运行速度也还行, 直到我开始编译我的ps1. 这个编译过程花了几十分钟, 作为对比, 我用手上的笔记本下载完依赖包后编译只要1.4秒, 这直接完全打消了我拿iPad去上班的念头. 看来这个东西最大的用途仍然只能是犯懒不想开电脑的时候能ssh连上内网的rpi去做一些维护操作.

SCS考试相关

上个周末考过了AWS Certified Security - Specialty, 简称是SCS. 分数比考SAP的稍低了一点点, 898分, 换成百分制是89分, 也可以了, 单项也都还满足要求. 虽然现在自己日常做的事情不少是和安全策略相关, 但是还是通过这个考试发现了自己的一些薄弱环节, 比如:

倒是日常接触比较多的服务/特性都没什么大问题, 果真是业精于勤荒于嬉, 或者说拳不离手曲不离口.

AWS跨账号更新一例

我构想出的基于Eventbridge的多账号管理方案已经基本成型了, 后面应该会单独成文. 这儿介绍里面的一小段工作. 如何用一个lambda来更新一个Cloudformation stack. 这个事情本身并不难做, 不过我先说下我们的背景吧.

依着前面说过, 我们跨账号管理的时候是通过发消息来进行, 而不是通常的跨账号assume-role, 我们认为这样更安全, 因为所有的操作都已经被预设好了. 这儿介绍的这段工作是更新一个日志账号里的stack, 比如, 我们仅有少数几个账号启用了Cloudfront, 我们希望允许这些账号将Cloudfront的日志归集到一个bucket里面去, 所以我们的bucket policy需要类似这样:

{% for account_name, account_id in accounts.items() %}
          - Sid: allow-from-{{ account_name }}-{{ account_id }}
            Effect: Allow
            Principal:
              AWS: "arn:aws:iam::{{ account_id }}:root"
            Action:
              - 's3:PutObject'
              - 's3:PutObjectAcl'
            Resource:
              - !Sub 'arn:aws:s3:::${CfrLogsBucket}/{{ account_id }}/*'
            Condition:
              StringEquals:
                's3:x-amz-acl': bucket-owner-full-control
{% endfor %}

这样各个账号的日志不会串, 即使某个账号被人拿到了权限, 也不会影响到其他账号的日志记录. 那么现在问题来了, 每次新添加一个需要写Cloudfront日志的AWS账号, 我们都需要更新这个bucket policy, 但是我们应该怎么更新呢? 我们有下面这样的bucket policy来避免任何人篡改这个bucket:

          - Sid: deny-modification
            Effect: Deny
            Principal: "*"
            Action:
              - 's3:Delete*'
              - 's3:PutBucket*'
            Resource:
              - !Sub 'arn:aws:s3:::${CfrLogsBucket}'
              - !Sub 'arn:aws:s3:::${CfrLogsBucket}/*'

做过这样的设置后, 只有这个AWS账号的root用户能够修改这个bucket policy了. 所以, 之前我们的更新方式是登录成root用户, 然后手工更新Cloudformation的模板, 这样自然不是一个合理的方式. 我们作出了决定, 希望有一个lambda能够从一个可信任的artifact bucket里拿到更新后的模板并应用. 此时, 这段deny-modification策略就成了问题. 研究了一段时间后发现, 上面的策略改成下面这样就可以了:

          - Sid: deny-modification
            Effect: Deny
            NotPrincipal:
              AWS:
                - !Sub "arn:aws:iam::${AWS::AccountId}:role/update-s3-stacks-role"
                - !Sub "arn:aws:sts::${AWS::AccountId}:assumed-role/update-s3-stacks-role/AWSCloudFormation"
            Action:
              - 's3:Delete*'
              - 's3:PutBucket*'
            Resource:
              - !Sub 'arn:aws:s3:::${CfrLogsBucket}'
              - !Sub 'arn:aws:s3:::${CfrLogsBucket}/*'

于是, 我们的整体解决方案是: 我们在一个管理账号里面给这个日志账号通过eventbridge发信息, 这个信息到达日志账号后, 会触发一个lambda. 这个lambda会使用一个service role(即前述代码中的update-s3-stacks-role)来更新Cloudformation的stack. 因此, 这个lambda的role除了有做一群cfn的action的权限外, 还有类似下面的policy:

      - PolicyName: iam-passrole
        PolicyDocument:
          Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action:
                - iam:PassRole
              Resource: !GetAtt CfnServiceRole.Arn
              Condition:
                StringLikeIfExists:
                  iam:PassedToService: cloudfomation.amazonaws.com

这样, 我们在调用CreateChangeset这个API的时候, 就可以把这个我们称为CfnServiceRole又即update-s3-stacks-role的Role当作ExecutionRoleName来交给Cloudformation了. 这个Service Role能够做所有的S3操作, 但是没法创建其他任何资源了. 这样能保证即使有任何入侵, 我们也不会丢文件. 最后的结果是, 我们通过这样一个我们认可的方式跨账号更新一个S3 bucket的policy.