深夜の怠惰な技術ブログ

日々の技術的な話題などを徒然なるままに

GitHub Actionsの実行に向けたTerraformによるAWS IAM Roleの作成について

はじめに

GitHub ActionsにてAWSリソースをIaC(Terraform、AWS CDK等々)によって構築する際、従来はGitHub Actions用のIAM Userを作成して、権限を付与する方法が一般的であったかと思います。 しかしながら、現在はIAM Roleによる権限付与の方法が確立されました。このIAM Roleの作成をTerraformによってどのように記述するのかをポイントに本投稿を記載します。

TerraformによるIAM Roleの作成

GitHub Actions用のIAM Roleを作成する際に必要となるコンポーネントは以下の3つとなります。

  • IAM ID Provider
  • IAM Role
  • IAM Policy

    IAM ID Provider

    まずは、ID Providerを作成します。これにより、AWSの外部ユーザIDにアカウント内のAWSリソースに対するアクセス許可を与えることができます。

resource "aws_iam_openid_connect_provider" "github" {
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["a031c46782e6e6c662c2c87c76da9aa62ccabd8e"]
  url             = "https://token.actions.githubusercontent.com"
}

client_id_list は対象者もしくはaudienceとも呼ばれるものを指定します。 ここでは、sts.amazonaws.com と記述しています。 これは、GitHub Actionsで利用する actions/configure-aws-credentials@v1 の要求からくるものです。

thumprint_listOpenID Connect Providerがキーを利用できるようにするドメインで使用されるX.509証明書の16進エンコードされたSHA-1ハッシュ値です。 AWSマネジメントコンソールからID Providerを作成する際には、ProviderのURLを入力すると動的に設定してくれますが、今回はTerraformによる設定のため記述が必要になります。

IAM Role

先にID ProviderのTerraformコードができたので、次にIAM Roleを作成します。 このIAM Roleの信頼関係では、先のID ProviderからのAssume Roleを許可する必要があります。 また、特定のGitHubリポジトリからのGitHub Actionsのみを許可するための設定も必要となります。 これらの設定を反映したTerraformコードが以下となります。

resource "aws_iam_role" "github" {
  name = "GithubActionRole"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["sts:AssumeRoleWithWebIdentity"]
        Principal = {
          Federated = aws_iam_openid_connect_provider.github.arn
        }
        Condition = {
          StringLike = {
            "token.actions.githubusercontent.com:sub" = "repo:<GitHub Organization>/<Repository Name>:*"
          }
        }
      }
    ]
  })
}

特定のGitHubリポジトリからのGitHub Actionsのみを許可する設定は、以下の部分に該当します。

Condition = {
  StringLike = {
    "token.actions.githubusercontent.com:sub" = "repo:<GitHub Organization>/<Repository Name>:*"
  }
}

ただし、これだと特定の単一GitHubリポジトリのみが対象となります。 そのため、例えば複数のGitHubリポジトリを指定したい場合には配列による指定が可能です。

Condition = {
  StringLike = {
    "token.actions.githubusercontent.com:sub" = [
      "repo:<GitHub Organization>/<Repository Name A>:*",
      "repo:<GitHub Organization>/<Repository Name B>:*",
    ]
  }
}

また、特定のGitHub Organizationの任意のリポジトリを指定することも可能となります。

Condition = {
  StringLike = {
    "token.actions.githubusercontent.com:sub" = "repo:<GitHub Organization>/*:*"
  }
}

いずれにせよ、上記のような Condition句 の記載がない場合にはどのようなリポジトリからのGitHub Actionsも対象となってしまうのでご注意ください。

IAM Policy

先に作成したIAM Roleに付与するIAM Policyを作成します。つまり、GitHub Actionsに許可するPolicyを設定するということです。 IAM Policyを作成するためのTerraformコードについてはTerraformのドキュメントや他ブログなどでも詳細な記述があると思いますので、ここでは割愛します。

GitHub Actionsの実行について

最後に、GitHub Actionsにて先に作成したIAM RoleへどのようにAssume Roleするのかをyamlファイルで記載します。

name: 'Sample'
on:
  push:
    branches:
      - main
env:
  AWS_REGION: 'ap-northeast-1'
jobs:
  cdk:
    name: 'Sample Action'
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ secrets.ROLE_ARN }}
          aws-region: ${{ env.AWS_REGION }}
      - name: AWS STS Get Caller Identity
        run: aws sts get-caller-identity

今回のようにID Providerを利用する場合には、permission: 以下の内容がまずは必要となります。 そして、要の部分は aws-actions/configure-aws-credentials@v1 です。 このモジュールの引数として role-to-assumeaws-region が必要となります。 この role-to-assume は先に作成したIAM RoleのARNを指定します。 ここでは、GitHubのSecretsに該当ARNを設定しているため、それを呼び出す記述になっています。

さいごに

いかがだったでしょうか。最近ではこれらの内容を紹介するブログが増えているように感じますが、それぞれの設定などを理解するのに少々時間が掛かりました。 また、IAM Role関連の作成はCloudFormationでの紹介が多く、Terraformユーザに少しでも役に立てれば幸いです。

CloudWatch AlarmをAWS ChatbotによりSlackに通知する方法

はじめに

今回は表題通り、CloudWatch AlarmSNSAWS Chatbotを利用したSlack通知の実現方法を記載していきます。 私自身はIaC(Infrastructure as Code)としてはTerraformを利用します。ただし、現在TerraformはAWS Chatbotに対応しておりません。 そのため、AWS ChatbotだけはAWS マネジメントコンソールで作成していきます。また、通知先となるSlack Channelについてはすでに作成済みであることとします。

アーキテクチャ

f:id:ymyuta:20211204145251p:plain
CloudWatch AlarmからSlack ChannelへのAWS Chatbotを利用した通知

CloudWatch Alarmの作成

まずは、CloudWatch Alarmの作成となります。 ここでは、ALB(Application Loadbalancer)TargetgroupにおけるHealthyHostCountに対して、しきい値を設けていきます。 なお、Targetgroupでは1つのHost(ECSにおけるTask)が実行されている状況が正常とします。

resource "aws_cloudwatch_metric_alarm" "sample" {
  alarm_name          = "SampleAlarm"
  alarm_description   = "Sample Alarm Verify For Slack Notification"
  comparison_operator = "LessThanThreshold"
  evaluation_periods  = 1
  datapoints_to_alarm = 1
  metric_name         = "HealthyHostCount"
  namespace           = "AWS/ApplicationELB"
  dimensions = {
    "LoadBalancer" = "app/<alb_name>/exmaple8e4b2d09"
    "TargetGroup"  = "targetgroup/<targetgroup_name>/exampled7739b8e7"
  }
  period        = 60
  statistic     = "Average"
  threshold     = 1
  alarm_actions = [var.cloudwatch_alarm_sns_topic_arn] // 後ほど作成するSNS Topicに対するARNとなります。 
  ok_actions    = [var.cloudwatch_alarm_sns_topic_arn] // 後ほど作成するSNS Topicに対するARNとなります。 
}

上記は、該当のCloudWatch Alarmを作成する上でのTerraformコードになります。ここで重要なポイントにしぼって説明します。

対象となるCloudWatch Metricsの指定方法

今回は先述の通り、対象のCloudWatch MetricsはALB(Application Loadbalancer)TargetgroupにおけるHealthyHostCountとなります。 これらを指定するのに必要な設定値としては、namespacedimensionsmetric_nameです。

しきい値の指定方法

しきい値を指定する設定はthresholdcomparison_operatorになります。 正常なHost数は1であるため、Host数が1未満となったら異常状態とするために、comparison_operatorはLEssThanThresholdとしています。

SNSとの連携

CloudWatch Alarmが取り得る状態としては、異常(Alarm)正常(OK)No Dataの3種類です。 それぞれの状態に遷移した際に、SNSへトピックを発行することができます。 状態ごとに発行先のSNSを指定することができますが、今回はすべて同じSNSを指定しています。 Terraformコードでは対象SNSのARNを記述することになります。

SNSの作成

CloudWatch Alarmがトピックを発行するためのSNSを作成します。

resource "aws_sns_topic" "sample" {
  name = "cloudwatch-alarm-topic"
}

resource "aws_sns_topic_policy" "sample" {
  arn = aws_sns_topic.sample.arn
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["sns:Publish"]
        Principal = {
          Service = "cloudwatch.amazonaws.com"
        }
        Resource = aws_sns_topic.sample.arn
        Condition = {
          ArnLike = {
            "aws:SourceArn" = "arn:aws:cloudwatch:<region>:<account_id>:alarm:<alarm_name>"
          }
        }
      }
    ]
  })
}

AWS Chatbotの作成

AWS Chatbotの設定については先述の通りAWS マネジメントコンソールにて実施していきます。 まずは、チャットクライアントの設定にてSlackを指定します。

SlackのPrivate Channelにおける対応について

ひとつだけ、対象のSlack ChannelがPublicの場合には設定はAWS Chatbotのみで完結します。 ただし、Private Channelの場合には対象のChannelに対してAWSユーザをInviteする必要があります。

f:id:ymyuta:20211205144847p:plain
AWS Chatbotにおけるチャットクライアントの設定
f:id:ymyuta:20211205144929p:plain
チャットクライントにおけるSlackの指定
設定を実施すると、Slackへのアクセス許可を求められるので、問題なければ承認を実施します。 問題無く連携が完了したら、新たなChannelを追加することで連携することができます。

さいごに

いかがだったでしょうか。シンプルな内容で学びもそれほど多くはないかもしれませんが、備忘のために記載しました。 引き続き、よろしくお願い致します。

This is Leanを読んで~その2~

はじめに

前回の投稿では、This is Leanを読んで~その1~と題して、リソース効率とフロー効率の概要をScrumの文脈で書いていきました。 今回はリソース効率におけるパフォーマンスへの影響を挙げ、フロー効率との完全なる両立が困難な理由を書いていければと思います。

リソース効率におけるパフォーマンスへの影響

まずは前回の投稿でのリソース効率について簡単に振り返ります。 Scrumを例にとった場合に、リソース効率を高めようとすると以下の図のような状態が予想されます。

f:id:ymyuta:20210923144016p:plain
リソース効率による状態
つまり、開始から完了までの時間が徐々に長くなる、また複数Itemに対するタスクが並列で処理されていくなどの事象が発生します。 これらの事象がパフォーマンスにどのように影響していくかを書いていきます。

長いスループット時間の影響

今までは開始から完了までの時間と書いていましたが、これをスループット時間と言います。 スループット時間とは、フローユニットに対する処理が開始してから完了するまでの時間を指します。 Scrumにおいては、ひとつのPBIをフローユニットといい、そのPBIへの処理が開始されてから完了するまでをスループット時間と呼ぶこととなると思います。 完了が何を指すのかは、Scrumチームにおける完了の定義(Definition of Done)によると思いますが、今回の投稿ではプロダクトを利用しているユーザに対して、PBIによる機能がリリースされたこととします。

スループット時間が長くなるとはどのようなことを意味するのでしょうか。 例えば、開発開始からリリースまでの時間が長くなります。すると、リリース対象の実装がどのようなものだったのかを思い出すことが必要になってくるかもしれません。 この思い出す作業が発生することにより、副次的なタスクとして、リリース対象の実装を別途ドキュメントとして書き出しておいたりといったものが追加される可能性もあります。 このような本来必要のないニーズ(上記の例でいえば、思い出す作業をスムーズにする)といったものを、本書では二次ニーズと呼び、スループット時間が長くなることで二次ニーズが発生しやすくなると書いてあります。 そして、このような二次ニーズにより不要なタスクが発生することも示唆しています。

不要なタスクが発生することで、本来注力すべきタスクに割く時間が減少してしまうのは、Scrumチームのパフォーマンス低下に結びつくのではないでしょうか。

多すぎるフローユニットの影響

リソース効率を高めようとした際には、上図からもわかるように、各engineerに対してフローユニットに関連するタスクに連続的に取り組んでいかなければなりません。つまり、フローユニットが多くなるのが常です。 そのため、Scrumチーム内で様々フローユニットに対するタスクが並列で実施されている状態となります。このような状態において発生する事象はどのようなものがあるでしょうか。

例えば、各engineerが並列するタスクにおいて、ひとつのGit Repositoryの各々のブランチで作業を実施していたとします。そのような場合にはコンフリクトやリベース作業などが発生しやすくなります。 コンフリクトの解消やリベース作業は本来不要なタスクだったかもしれません。並列するタスクを実施することにより、ムダなタスクが発生する可能性が高まることになります。 また、あるengineerが別のengineerが実施したタスクに対して質問したとします。しかし、質問されたengineerは現在はまた別のタスクを実施しており、その質問を答えるために頭の切り替えをしなければならなくなります。 このように、スイッチングコストが高まる可能性もでてきてしまいます。

つまり、フローユニットが多くなると、長いスループット時間の影響と同様にムダなタスクが発生することに加えて、スイッチングコストが高まることによるパフォーマンス低下が生まれてしまうかもしれません。

リソース効率とフロー効率の両立は困難

上記ではリソース効率を高めることで発生し得るパフォーマンスの低下について書きました。 これらの原因としては、長いスループット多すぎるフローユニットなどが挙げられます。 この原因を解消するためのアプローチがフロー効率を高めることとなります。 そのため、フロー効率を高めようとすると必然的にリソース効率は低くなるのです。

f:id:ymyuta:20211004090947p:plain
リソース効率とフロー効率のマトリックス
上図のように、理想はリソース効率とフロー効率がお互いに高い星印の部分にチームの効率を近づけようとする。しかしながら、それぞれの効率における両立は理論上困難なため、現実的には点線で記載してある部分を目指します。

さいごに

いかがでしたでしょうか。リソース効率を高めた際の影響については、読んでいただいた皆さまにも覚えがあることだったではないでしょうか。 また、リソース効率を高めた際のパフォーマンス低下を避けるための方法としてのフロー効率についても書きました。これによって、リソース効率とフロー効率の両立が困難なことも記載しました。

This is Leanを読んで~その1~

はじめに

先日This is Leanを読了しました。この本を読むきっかけとしては、アジャイル開発やScrumという文脈で度々耳にすることもあるLeanという言葉について、改めて自分の認識を固めておきたかったためです。 本ブログではこの本を通して語られる内容に対して、ソフトウェア開発、アジャイル、Scrumでの経験に落とし込んで、僕なりの整理をしていきたいと思います。

アジェンダ

This is Leanを読んでは以下のアジェンダについて、複数の投稿に分けていこうと考えてます。

  1. リソース効率とフロー効率について
  2. 両効率を同時に満たすことはできない
  3. Leanとは

今回は、1. リソース効率とフロー効率についてをまとめていきます。

リソース効率とフロー効率について

リソース効率

リソース効率とは、従来効率と呼ばれる多くの場合に意味しているものとなります。具体的には、ある業務を担当している担当者に対して稼働率が100%に近づくように担当業務を割り振るための効率化を指します。 つまり、ある価値を生じさせる機能(人、機械など)にスポットを当てた効率性となります。 多くの企業において、セールス部門、エンジニアリング部門、企画部門など、機能ごとに組織化してこのリソース効率を高めるための構造を構築しています。

Scrumにおけるリソース効率

リソース効率という観点から、Scrumを見ていくことにします。以下の図の通り、あるScrumチームにはInfra engineer、Backend engineer、Frontend engineerがいると仮定します(engineerの名称については簡略化のためこのように記載しております、ご容赦ください)。それぞれのPBI(Product Backlog Item)には、各種Infra、Backend、Frontendに関するタスクが存在します。リソース効率を念頭において各PBIに取り組むとすると、担当であるタスクに注力することとなります。

f:id:ymyuta:20210923135942p:plain
Scrumにおけるリソース効率

例えば、Infra engineerにスポットを当ててみると、Sprint内でInfra関連のタスクにリソースを全投入しようとしています。 プロダクトの採算を管理している事業部がPO(Product Owner)の場合には、リソース効率を高めることを要望してくることがありました(engineerにももちろん人件費がかかっているのでわからなくもない話しではありますが)。 具体的にはSprint外のItemにおけるタスクを実施するなどといった要望です。そもそもScrumとしてのルールから逸脱している要望ですが、実際にあった話しです。

リソース効率を高めた際に起こり得ること

では、リソース効率を高めた場合にどのようなことが発生するのでしょうか?ここで簡単な例を挙げます。 以下の図に示す通り、リソース効率を高めようとすると、各engineerはそれぞれのタスクに取り組みます。

f:id:ymyuta:20210923144016p:plain
リソース効率による事象
すると、あるItemに対しての開始から完了までの時間が徐々に長くなっていくのがわかるかと思います。 また、あるタイミングにおいては複数Itemに対するタスクが並列で処理されていることもあります。 これらリソース効率により発生する事象によって、Scrumチームのパフォーマンスにどのような影響が発生するかは、2. 両効率を同時に満たすことはできないでお伝えできればと思います。

フロー効率

上記でリソース効率はある価値を生じさせる機能にスポットを当てた効率性ということを書きました。 一方で、フロー効率とは、あまり耳馴染みのない言葉かもしれませんが、ある価値を付与する対象への効率性ということができます。 また、ある価値を付与する対象のことをフローユニットと呼びます。

Scrumにおけるフローユニットと効率性

リソース効率でも行ったように、Scrumという観点におけるフロー効率を見ていきたいと思います。 フロー効率はフローユニットへの効率性を高めるものです。ScrumにおけるフローユニットはPBIとなることが多いと思います。

f:id:ymyuta:20210923144658p:plain
フロー効率による事象
ご覧のように、リソース効率で発生していた事象である開始から完了までの時間安定し、複数Itemに対するタスクの並列処理解消されたことがわかると思います。 実際にScrumにおいて、このフロー効率を高めるプラクティスは種々ありますが、それは別のブログや書籍にお任せしようと思います。

さいごに

如何だったでしょうか。本投稿では、リソース効率とフロー効率について、Scrumという観点から情報をまとめてみました。 今回の内容に関連して、モブプログラミングなどのプラクティスとの関連性も垣間見えた方がいらっしゃるかと思いますが、This is Leanからは少し蛇足となりそうだったので割愛してます。 ただし、実際にScrumで実践しているプラクティスの背景や動機を考える上のスタートラインとしての意義はあったのかな、と個人的には思ってます。 僕が整理したい部分にフォーカスしてますので、網羅性などはあまりありませんが誰かのお役に立てれば幸いです。

はじめに

お礼

数あるブログの中から、このブログにアクセスしていただき、ありがとうございます。 本投稿では、今後どのような内容を記載していこうかということを簡単ですがお伝えできればな、と思っています。

このブログの目的について

記載内容

基本的には、ソフトウェア開発についての内容を記載していこうかと思ってます。 ただし、そこまで大仰な話しではなく、僕自身が実際に手を動かしていく中で直面した壁などについて、備忘録的に書いていきたいです。 どこかで、僕が体験したことと同じような壁にぶち当たって、困っている方の一助になれれば幸いです。

更新頻度

仕事などの関係から多少前後はするかもしれませんが、1週間に1回は更新したいと思います。

さいごに

継続は力なり、投稿を積み重ねることで、僕自身の知識の深化もできればいいな。 みなさん、よろしくお願い致します。