heptio-authenticator-awsの使い方

## heptio-authenticator-awsとは

TL;DR; [Token Review API](https://qiita.com/hiyosi/items/b6a1d07b30ff7dff1961)とAWS STS, IAMを使って、IAMの権限でK8S APIを叩ける用にするツールです

## もう少し長い説明

> heptio/authenticator: A tool for using AWS IAM credentials to authenticate to a Kubernetes cluster (proof of concept)
> https://github.com/heptio/authenticator

authenticatorは、IAMクレデンシャルでK8Sの認証を通すためのツールです。

> If you are an administrator running a Kubernetes cluster on AWS, you already need to manage AWS credentials for provisioning and updating the cluster. By using kubernetes-aws-authenticator, you avoid having to manage a separate credential for Kubernetes access. AWS IAM also provides a number of nice properties such as an out of band audit trail (via CloudTrail) and 2FA/MFA enforcement.

AWS管理者は既にAWSクレデンシャルを複数管理してると思います。KubernetesのAPIクレデンシャルを2重管理したくないので、AWSクレデンシャルをKubernetesへの認証に使えたらよいでは？という考えて開発されたようです（わかる）。

あと、K8S標準の認証方法だとMFAに対応してないですが、この方法ならAWS側でMFA対応できるのでよりセキュア、かつCloudTrailで監査ログをとれるところも利点として挙げられています。

## 手順(ソースからクロスビルドして動かすところまで)

ソースを取得

```
$ cd
$ git clone git@github.com:heptio/authenticator.git go/src/github.com/heptio/authenticator
```

goreleaserのインストール

```
$ go get -u -v github.com/goreleaser/goreleaser
```

ローカルマシンで動かすためのauthenticatorをビルド

```
$ cd go/src/github.com/heptio/authenticator/
$ ls
CODE_OF_CONDUCT.md	Dockerfile		Gopkg.toml		Makefile		ca-certificates.crt	example.yaml		pkg
CONTRIBUTING.md		Gopkg.lock		LICENSE			README.md		cmd			main.go			vendor
# make build
$ mv heptio-authenticator-aws /usr/local/bin/
```

ビルドされるコンテナイメージのレポジトリを変更

```
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index 6e57d38..c964228 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -13,33 +13,33 @@ builds:
       - CGO_ENABLED=0
 
 dockers:
-  - image: gcr.io/heptio-images/authenticator
+  - image: mumoshu/authenticator
     binary: heptio-authenticator-aws
     dockerfile: Dockerfile.scratch
     tag_templates:
      - "{{ .Tag }}-scratch"
      - "{{ .Tag }}"
     latest: false
-  - image: gcr.io/heptio-images/authenticator
+  - image: mumoshu/authenticator
     binary: heptio-authenticator-aws
     dockerfile: Dockerfile.alpine-3.6
     tag_templates:
      - "{{ .Tag }}-alpine-3.6"
     latest: false
-  - image: gcr.io/heptio-images/authenticator
+  - image: mumoshu/authenticator
     binary: heptio-authenticator-aws
     dockerfile: Dockerfile.alpine-3.7
     tag_templates:
      - "{{ .Tag }}-alpine-3.7"
      - "{{ .Tag }}-alpine"
     latest: false
-  - image: gcr.io/heptio-images/authenticator
+  - image: mumoshu/authenticator
     binary: heptio-authenticator-aws
     dockerfile: Dockerfile.debian-jessie
     tag_templates:
      - "{{ .Tag }}-debian-jessie"
     latest: false
-  - image: gcr.io/heptio-images/authenticator
+  - image: mumoshu/authenticator
     binary: heptio-authenticator-aws
     dockerfile: Dockerfile.debian-stretch
     tag_templates:
```

バイナリとKubernetesにデプロイする側のauthenticatorコンテナイメージをビルド

```console
$ eval $(minikube docker-env)
$ make build
```

クラスタがアクセスできるDocker Registryにイメージをアップロード

```console
$ docker push mumoshu/authenticator:v0.2.0-pre-alpine
```

## config.yamlの作成

このファイルがauthenticatorのサーバ、クライアントの共通設定ファイルです。

```yaml
# a unique-per-cluster identifier to prevent replay attacks (see above)
clusterID: k8s1.example.com

# server listener configuration
server:
  # a mapping of IAM role (specified by ARN) to a list of Kubernetes group names
  mapRoles:
  - roleARN: arn:aws:iam::<accountid>:<rolename>
    username: kubernetes-admin
    groups:
     - system:masters
```

- `mapRoles`にはどのIAMロールをK8Sのどのusername & groupsにマッピングするかを書く
- `mapRoles`にIAMロールマッピングが複数ある場合は`kubernetes-aws-authenticator token -r <ロール名`のようにロールを選択できる
- `defaultRole`が`token`コマンドの`-r`フラグを省略した場合のデフォルトロール名

## 必要なファイルの生成

まず、heptio-authenticator-awsで必要なファイルの生成。

- key.pem
- cert.pem
- heptio-authenticator-aws.kubeconfig

```console
$ heptio-authenticator-aws init -i <fqdn>
INFO[2017-12-03T23:21:55+09:00] generated a new private key and certificate   certBytes=810 keyBytes=1190
INFO[2017-12-03T23:21:55+09:00] saving new key and certificate                certPath=cert.pem keyPath=key.pem
INFO[2017-12-03T23:21:55+09:00] loaded existing keypair                       certPath=cert.pem keyPath=key.pem
INFO[2017-12-03T23:21:55+09:00] writing webhook kubeconfig file               kubeconfigPath=heptio-authenticator-aws.kubeconfig
INFO[2017-12-03T23:21:55+09:00] copy cert.pem to /var/heptio-authenticator-aws/cert.pem on kubernetes master node(s)
INFO[2017-12-03T23:21:55+09:00] copy key.pem to /var/heptio-authenticator-aws/key.pem on kubernetes master node(s)
INFO[2017-12-03T23:21:55+09:00] copy heptio-authenticator-aws.kubeconfig to /etc/kubernetes/heptio-authenticator-aws/kubeconfig.yaml on kubernetes master node(s)
INFO[2017-12-03T23:21:55+09:00] configure your apiserver with `--authentication-token-webhook-config-file=/etc/kubernetes/heptio-authenticator-aws/kubeconfig.yaml` to enable authentication with heptio-authenticator-aws
```

## kube-awsを使う場合の設定

config.yamlをBASE64エンコード

```console
cat heptio-authenticator-aws.kubeconfig| base64 | pbcopy
```

`cluster.yaml`にapiserverに設定するwebhook-token-review-endpointのURLを書く。

```yaml
experimental:
  webhook:
    enabled: true
    cacheTTL: 1m0s
    configBase64: <heptio-authenticator-aws.kubeconfigをBASE64エンコードしたもの>
```

クラスタを更新する。

```console
$ kube-aws validate
$ kube-aws update
```

## heptio-authenticator-awsのデプロイ

以下の３つを作成する。

- configmap
- secret
- daemonset

**configmap**:

```console
$ mkdir config-dir
$ mv config.yml config-dir/
$ kubectl create configmap heptio-authenticator-aws --from-file ./config-dir --namespace kube-system
```

**secret**:

```console
$ mkdir secret-dir
$ mv cert.pem key.pem secret-dir/
$ kubectl create secret generic heptio-authenticator-aws --from-file ./secret-dir --namespace kube-system
```

**daemonset**:

```yaml:heptio-authenticator-aws.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  namespace: kube-system
  name: heptio-authenticator-aws
  labels:
    k8s-app: heptio-authenticator-aws
spec:
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        k8s-app: heptio-authenticator-aws
    spec:
      # run on the host network (don't depend on CNI)
      hostNetwork: true

      # run on each master node
      nodeSelector:
        node-role.kubernetes.io/master: ""
      tolerations:
      - effect: NoSchedule
        key: node.alpha.kubernetes.io/role
        operator: Equal
        value: "master"
      - key: CriticalAddonsOnly
        operator: Exists

      # run `heptio-authenticator-aws server` with three volumes
      # - config (mounted from the ConfigMap at /etc/heptio-authenticator-aws/config.yaml)
      # - state (persisted TLS certificate and keys, mounted from the host)
      # - output (output kubeconfig to plug into your apiserver configuration, mounted from the host)
      containers:
      - name: heptio-authenticator-aws
        image: mumoshu/authenticator:v0.2.0-pre-alpine
        args:
        - server
        - --config=/etc/heptio-authenticator-aws/config.yaml
        - --state-dir=/var/heptio-authenticator-aws
        resources:
          requests:
            memory: 20Mi
            cpu: 10m
          limits:
            memory: 20Mi
            cpu: 100m
        volumeMounts:
        - name: config
          mountPath: /etc/heptio-authenticator-aws/
        - name: state
          mountPath: /var/heptio-authenticator-aws/
        - name: output
          mountPath: /etc/kubernetes/heptio-authenticator-aws/

      volumes:
      - name: config
        configMap:
          name: heptio-authenticator-aws
      - name: state
        secret:
          secretName: heptio-authenticator-aws
      - name: output
        emptyDir: {}
```

```
$ kubectl --namespace kube-system create -f heptio-authenticator-aws.yaml
```

## 使い方

Kubernetes APIトークンの取得

```
$ heptio-authenticator-aws -c config-dir/config.yaml token
```

heptio-authenticator-awsから取得したトークンを使ってkubectlを実行

```
$ kubectl --token "$(heptio-authenticator-aws -c config.yaml token) get no
```

## おまけ: minikubeで動作確認

`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`などの環境変数をheptio-authenticator-awsのPodに設定する。

その状態で、以下のようなスクリプトでTokenReview APIを模したリクエストを送ることで、heptio-authenticator-awsが想定通り動いているかどうかわかる。

```bash:test.sh
#!/usr/bin/env bash

# Usage:
#   ./test.sh

if [ "$(hostname)" != minikube ]; then
  dist/darwin_amd64/heptio-authenticator-aws token -c config-dir/config.yaml > token
  minikube ssh $(cd $(dirname $0)/; pwd)/test.sh
else
  dir=$(dirname $0)
  curl \
    --insecure \
    -H 'Content-Type: application/json' \
    -d '{"apiVersion": "authentication.k8s.io/v1","kind": "TokenReview","spec": {"token": "'$(cat $dir/token)'"}}' \
    https://127.0.0.1:21362/authenticate
fi
```