GeekFactory

int128.hatenablog.com

GitHub GraphQL APIで新しいブランチを作成する

GitHub GraphQL APIで新しいブランチを作成できるようになっていたので試してみました。本記事の内容はGraphQL API Explorerで実行できます。

リポジトリに新しいブランチやタグを作成するにはcreateRef mutationを利用します。createRefを実行するには以下の引数が必要です。

name (String!) The fully qualified name of the new Ref (ie: refs/heads/my_new_branch).

oid (GitObjectID!) The GitObjectID that the new Ref shall target. Must point to a commit.

repositoryId (ID!) The Node ID of the Repository to create the Ref in.

リポジトリID(repositoryId)とコミットID(oid)を取得するには以下のクエリを実行します。リポジトリ名やブランチ名は必要なものに置き換えてください。

query GetCommitID {
  repository(owner: "int128", name: "sandbox") {
    id
    ref(qualifiedName: "refs/heads/master") {
      target {
        oid
      }
    }
  }
}
{
  "data": {
    "repository": {
      "id": "MDEwOlJlcG9zaXRvcnk2OTgzMjM2Ng==",
      "ref": {
        "target": {
          "oid": "7a59fd9a6334706b942f1707531a0cf8a8523ce7"
        }
      }
    }
  }
}

クエリの実行結果からリポジトリIDは MDEwOlJlcG9zaXRvcnk2OTgzMjM2Ng==、コミットIDは 7a59fd9a6334706b942f1707531a0cf8a8523ce7 であることが分かります。これらのIDをcreateRefに渡します。

以下のmutationを実行するとexample1ブランチが作成されます。

mutation CreateBranch {
  createRef(input: {repositoryId: "MDEwOlJlcG9zaXRvcnk2OTgzMjM2Ng==", name: "refs/heads/example1", oid: "7a59fd9a6334706b942f1707531a0cf8a8523ce7"}) {
    clientMutationId
  }
}

REST APIの場合は1回のリクエストでブランチ作成を実行できますが、GraphQLの場合はqueryとmutationで2回のリクエストが必要です。

Kubernetes DashboardとAWS IAM認証

Amazon EKS #1 Advent Calendar 2019の13日目です。今日はKubernetes DashboardとIAM認証についてお話しします。

背景

Kubernetesクラスタをチームで運用する場合、チーム全員がコマンドラインツールに習熟しているとは限らないため、GUIツールを併用することが望ましいです。新しく参画したメンバはKubernetesの概念に不慣れかもしれません。初学者はコマンドラインツールとGUIツールを併用することで、新しい概念を理解しやすくなり、効率的に学習を進められます。

KubernetesGUIツールはいろいろありますが、まずは公式のKubernetes Dashboardを使ってみましょう。慣れてきたら別のGUIツールを探してみましょう。iOSのアプリもあります。

f:id:int128:20191212220309p:plain
Kubernetes Dashboard

課題

AWS公式チュートリアルでは、Service Accountを利用してEKSクラスタ上のKubernetes Dashboardにアクセスする方法が紹介されています。Kubernetes Dashboardを開くと下図のような入力画面が表示されるので、Service Accountのトークンを入力します。

f:id:int128:20191212220342p:plain
トークンの入力画面

チームでクラスタを利用する場合、Service Accountを共有すると以下のような課題があります。

  1. ユーザに応じた適切な権限付与ができない(アクセス制御)
  2. EKS Control Planeのログには同じService Accountが記録されるため、どのユーザが何の操作を行ったかを識別できない(ログ監査)
  3. 新規ユーザに安全な手段でトークンを共有する必要がある(Onboarding)
  4. ユーザがチームを離れた場合でもトークンが使えてしまう(Offboarding)

kubectlと同様にKubernetes DashboardでもIAM認証が使えると、これらの課題を解決できます。

本稿では、IAM認証を利用してKubernetes Dashboardにアクセスする方法を紹介します。

やってみよう

1. Kubernetes Dashboardをデプロイする

Kubernetes DashboardHelm Chartを利用すると簡単にデプロイできます。以下のコマンドを実行します。

helm install stable/kubernetes-dashboard --namespace kube-system --name kubernetes-dashboard

Helmを利用しない場合は、以下のManifestをデプロイします。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml

2. kauthproxyをインストールする

kauthproxyコマンドはHomebrewからインストールできます。

brew install int128/kauthproxy/kauthproxy

Krewというプラグインマネージャを利用している場合は、以下のコマンドでインストールできます。

kubectl krew install auth-proxy

3. Kubernetes Dashboardを開く

Kubernetes Dashboardを開くには以下のコマンドを実行します。

kubectl auth-proxy -n kube-system https://kubernetes-dashboard.svc

このコマンドを実行すると、自動的にブラウザが開いてKubernetes Dashboardが表示されます。もしブラウザが表示されない場合は http://localhost:18000 を開いてください。

Kubernetes Dashboardはログイン済みの状態で表示されます。トークンを入力する必要はありません。

動作原理

aws-iam-authenticator

EKS Control Planeにはaws-iam-authenticatorが組み込まれており、KubernetesのUser AccountとIAMのユーザを紐づける役割を果たしています。詳しくは7日目に id:katainaka0503 さんが書かれた記事が参考になります。

katainaka0503.hatenablog.com

EKSの推奨手順にしたがってkubeconfigを設定すると、kubectlコマンドを実行した契機でaws-iam-authenticatorが呼び出されます。aws-iam-authenticatorはSTSからトークンを取得し、標準出力を経由してkubectlコマンドにトークンを返します。kubectlコマンドはトークンを利用してEKS Control PlaneのAPIサーバにアクセスします。この一連の動作はEKS独自のものではなく、Kubernetesclient-go credential pluginsを利用しています。

詳しくは下記のスライドを参照ください。

speakerdeck.com

Kubernetes Dashboard

Kubernetes Dashboardは自身で認証の仕組みを持たず、HTTPリクエストに含まれるトークンをそのままAPIサーバに渡す設計になっています。したがって、aws-iam-authenticatorが取得したトークンをHTTPリクエストに付加することで、IAMユーザとしてKubernetes Dashboardにアクセスできます。

Kubernetes Dashboardの手前にリバースプロキシを入れると下図のようになります。

f:id:int128:20191212215909p:plain
Kubernetes DashboardKubernetes APIサーバの関係

ここまでくると、kauthproxyが何をやっているか想像がつくかもしれません。

kauthproxy

kauthproxyにはリバースプロキシとポートフォワードの機能があります。

f:id:int128:20191210103408p:plain
kauthproxyの構成

kauthproxyがやっていることは以下の3点です。

  1. aws-iam-authenticatorからトークンを取得する。
  2. Kubernetes DashboardのPodにポートフォワードする。
  3. リバースプロキシでHTTPリクエストのauthorizationヘッダにトークンを付加する。

kauthproxyはEKSに限らず利用できる汎用的なツールになっています。1ではclient-go credentials pluginからトークンを取得しているため、aws-iam-authenticatorだけでなくOpenID Connectでも動作します。また、authorizationヘッダを利用するアプリケーションであれば動作します。

まとめ

kauthproxyを利用すると、IAM認証を利用してKubernetes Dashboardにアクセスできます。

github.com

GitLab CI/CDでtfnotifyを使う

mercari/tfnotifyがv0.3.2でGitLab CI/CDに対応したので試してみました。個人的には待望の機能追加です。tfnotifyを利用すると、GitLab CI/CDでTerraformを実行した結果をMerge Requestのコメントに反映できます。いちいちジョブの結果を見に行かなくてよいので便利です。

Getting Started

以下のステップでGitLabとtfnotifyを設定します。

  1. Personal Access Tokenの設定
  2. tfnotifyの設定
  3. GitLab CI/CDの設定

1. Personal Access Tokenの設定

tfnotifyはGitLab APIを利用してCommitにコメントを書き込みます。tfnotifyがGitLab APIにアクセスできるように、環境変数でPersonal Access Tokenを渡します。

User Settingsを開き、新しいPersonal Access Tokenを生成します。スコープはapiのみでよいです。

リポジトリのCI/CD Settingsを開き、以下の環境変数を追加します。

  • Key: GITLAB_TOKEN
  • Value: 先ほど生成したPersonal Access Tokenの文字列
  • Masked: yes

2. tfnotifyの設定

.tfnotify.yaml を作成します。ここでは、tfnotifyのREADMEに記載されている設定例をそのまま利用します。

ci: gitlabci
notifier:
  gitlab:
    token: $GITLAB_TOKEN
    base_url: https://gitlab.example.com
    repository:
      owner: OWNER
      name: NAME
terraform:
  fmt:
    template: |
      {{ .Title }}

      {{ .Message }}

      {{ .Result }}

      {{ .Body }}
  plan:
    template: |
      {{ .Title }} <sup>[CI link]( {{ .Link }} )</sup>
      {{ .Message }}
      {{if .Result}}
      <pre><code> {{ .Result }}
      </pre></code>
      {{end}}
      <details><summary>Details (Click me)</summary>
      <pre><code> {{ .Body }}
      </pre></code></details>
  apply:
    template: |
      {{ .Title }}
      {{ .Message }}
      {{if .Result}}
      <pre><code> {{ .Result }}
      </pre></code>
      {{end}}
      <details><summary>Details (Click me)</summary>
      <pre><code> {{ .Body }}
      </pre></code></details>

https://gitlab.com を利用している場合は base_url は設定しなくてもOKです。OWNER, NAMEはリポジトリのパスに合わせて修正してください。

3. GitLab CI/CDの設定

terraformと同時にtfnotifyを実行するように .gitlab-ci.yml を書き換えます。planの例を下記に示します。

stages:
  - build

terraform_plan:
  stage: build
  image:
    name: hashicorp/terraform:0.12.8
    entrypoint:
      - /usr/bin/env
  script:
    # Install tfnotify
    - apk add --upgrade curl
    - curl -fL -o /tmp/tfnotify.tar.gz https://github.com/mercari/tfnotify/releases/download/v0.3.3/tfnotify_0.3.3_linux_amd64.tar.gz
    - tar -C /usr/bin -xzf /tmp/tfnotify.tar.gz
    # Run Terraform
    - cd terraform/
    - terraform --version
    - terraform init
    - terraform fmt | tfnotify fmt
    - terraform plan -out=plan.tfplan | tfnotify plan
  artifacts:
    name: plan
    paths:
      - terraform/plan.tfplan
  cache:
    paths:
      - terraform/.terraform

tfnotifyはGitHub Releasesのバイナリを利用します。hashicorp/terraform イメージにはcurlコマンドが含まれていないため、apkコマンドでcurlをインストールする必要があります。デフォルトではカレントディレクトリにある .tfnotify.yaml を読みに行くので、カレントディレクトリに注意してください。

動作確認

上記の変更をコミットし、新しいMerge Requestを作成します。うまくいけば、Merge Requestにコメントが書き込まれます。