AWSコンソールのログインが面倒なのでSORACOM Kryptonを使う

# はじめに

AWSコンソールのログインがめんどい。
MFAにしてるともっとめんどい。
なんかこう簡単にログインする方法って、無いの？

ということでSORACOM Kryptonです。

# SORACOM Kryptonとは

> SORACOM Krypton は セキュアプロビジョニングサービスです。
SORACOM が発行する SIM と SORACOM プラットフォーム上に構築した SIM 認証基盤を使用し、さまざまなクラウドサービスに接続するためのプロビジョニング（初期設定）をセキュアに実現するサービスです。

https://soracom.jp/services/krypton/

SIMカードというのはなんか良く分からないけど携帯電話に必要なやつ、みたいな認識ですが、実は耐タンパ性にすぐれたセキュリティチップです。SIMの中には認証鍵が入っており、携帯通信時にはこの鍵を用いて認証されています。そのため携帯電話はどんな端末を使ってもそのSIMの番号として電話したり、通信したりすることができるようになっています。また、この認証をもとに暗号鍵を交換して、3GやLTE通信などを暗号化しているため、安全に携帯電話の通信ができています。

このSIMをIoTデバイスの認証に利用しようというのがSORACOM Kryptonの基本的な発想です。例えばIoTではAWS IoTがよく使われますが、AWS IoTではデバイス１つ１つに対して個別のクライアント証明書を発行し、保存する必要がありますが、この作業は中々手間ですし、間違えて書き込んでしまうなどのリスクもあります。SORACOM Kryptonを使用すると、そのSIMに結びついたクライアント証明書を簡単に発行できるため、デバイス個別に証明書を用意する必要がなくなるため、製造時の工数と認証情報流出や書き込みミスなどのリスクを下げることができる、というものです。

また、SORACOM BeamなどのサービスはSORACOM Air回線を使用することが前提となっていますが、SORACOM KryptonはWi-Fiや有線LANなどのインターネット回線からでも利用することができるため、通信費を抑えられる、携帯電波が入らない場所でも使える、などのメリットがあります。

# Amazon Cognito

SORACOM KryptonはAWS IoTの他にAmazon Cognitoの認証プロバイダーとして使用することもできます。Amazon Cognitoとは

> Amazon Cognito は、ウェブアプリケーションやモバイルアプリケーションの認証、許可、ユーザー管理をサポートしています。ユーザーは、ユーザー名とパスワードを使用して直接サインインするか、Facebook、Amazon、Google、Apple などのサードパーティーを通じてサインインできます。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/what-is-amazon-cognito.html

と記載されています。これを使うことで、たとえばFacebookの認証情報を用いて、その認証されたユーザーに対してS3やEC2などのAWSのサービスを許可する、ということができます。

SORACOM Kryptonと組み合わせると、SIMの所有者はSIMに紐付けられたAWSサービスが使える、ということになります。

# フェデレーションを使ったログイン

プログラムだけ利用するなら上記の方法でよいのですが、僕はまだAWSレベルが低いのでマネジメントコンソールが使いたいです。これには以下のページで説明されているフェデレーション（認証連携）を使ったコンソールへのアクセス許可が利用できます。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html

簡単に手順を説明すると以下のようになります。

1. なんらかの方法で一時的な認証情報を取得する (今回はSORACOM Kryptonで取得する)
2. 一時的認証情報を使ってフェデレーションエンドポイントからサインイントークンを取得する
3. サインイントークンを使ってログインする

# 準備

以下の準備をします。

- SORACOM IoT SIM
- SIMカードリーダー
- Amazon Cognitoの設定
- IAMユーザーの設定
- SORACOM Kryptonの設定
- Krypton CLI

SIMは「SORACOM IoT SIM(グローバルSIM)」でないと、セルラー回線を使わない認証ができないことに注意しましょう。

SIMカードリーダーは、SIMが読めるものであれば概ね大丈夫だと思いますが、今回は[ALCEY ICR05](https://www.amazon.co.jp/Alcey-ICR05-FC-Alcey%E3%83%9D%E3%83%BC%E3%82%BF%E3%83%96%E3%83%AB%E4%B8%80%E4%BD%93%E5%9E%8B-B-CAS%E3%83%BB%E4%BD%8F%E5%9F%BA%E3%82%AB%E3%83%BC%E3%83%89%E3%81%AA%E3%81%A9%E5%AF%BE%E5%BF%9C-USB%E5%85%B1%E6%9C%89%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9CAC%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%82%AB%E3%83%BC%E3%83%89%E3%83%AA%E3%83%BC%E3%83%80%E3%83%BC/dp/B01MDS3SWD)を使いました。SIMはカード状態でもチップの状態でも両方使用可能です。(ちなみにSDカードリーダーとしても使えます)今回はカード状態で使用しました。

![IMG_20200108_003626.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/7e9197af-3385-d6dd-5438-8d0be7a9d33b.jpeg)

Cognito、IAMユーザー、Kryptonの設定は、以下のページのステップ1〜3までを実施しました。
https://dev.soracom.io/jp/start/krypton_cognito/

Krypton CLIは[リリースページ](https://github.com/soracom/krypton-client-go/releases)からのダウンロード、もしくはGo言語開発環境があれば、

```bash
go install github.com/soracom/krypton-client-go/cmd/krypton-cli
```

でインストールします。

# コード

以下のページを参考にさせていただきました。
https://dev.classmethod.jp/cloud/aws/aws-management-console-login-without-iam-password/

動作OSはMac OSです。curlとjqを使っていますので、インストールされていない場合はインストールしてから実行します。

```bash
#!/bin/bash
set -e

# urlencode用のfunction定義
urlencode() {
  local length="${#1}"
  for (( i = 0; i < length; i++ )); do
    local c="${1:i:1}"
    case $c in
      [a-zA-Z0-9.~_-]) printf "$c" ;;
      *) printf '%%%02X' "'$c"
    esac
  done
}

# KryptonによるCognito認証情報の取得
KRYPTON_TOKEN=$(krypton-cli -operation generateAmazonCognitoSessionCredentials)
SESSION_ID=$(echo ${KRYPTON_TOKEN} | jq -r .credentials.accessKeyId)
SESSION_KEY=$(echo ${KRYPTON_TOKEN} | jq -r .credentials.secretKey)
SESSION_TOKEN=$(echo ${KRYPTON_TOKEN} | jq -r .credentials.sessionToken)

# SigninToken取得
JSON_FORMED_SESSION="{\"sessionId\":\"${SESSION_ID}\",\"sessionKey\":\"${SESSION_KEY}\",\"sessionToken\":\"${SESSION_TOKEN}\"}"
SIGNIN_URL="https://signin.aws.amazon.com/federation"
GET_SIGNIN_TOKEN_URL="${SIGNIN_URL}?Action=getSigninToken&SessionType=json&Session=$(urlencode ${JSON_FORMED_SESSION})"
SIGNIN_TOKEN=$(curl -s "${GET_SIGNIN_TOKEN_URL}" | jq -r .SigninToken)

# LOGIN URLの出力
ISSUER_URL="https://mysignin.internal.mycompany.com/"
CONSOLE_URL="https://console.aws.amazon.com/"
LOGIN_URL="${SIGNIN_URL}?Action=login&Issuer=$(urlencode ${ISSUER_URL})&Destination=$(urlencode ${CONSOLE_URL})&SigninToken=$(urlencode ${SIGNIN_TOKEN})"
open ${LOGIN_URL}
```

はい、それではSIMカードリーダーを挿して、実行してみましょう。

・・・

10秒くらいでログインできました。

![スクリーンショット 2020-01-08 0.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/90c43d3f-2db5-8fec-64e9-9c668fe688ba.png)

Cognitoに設定したロールで、フェデレーションログインしていることがわかります。
ロールに対して許可されたサービスを使うことができます。

これでSIMリーダー挿してコマンド一発で簡単にログイン出来るようになりましたね！

# おわりに

これって一要素認証だな。。