🎄

[Day.25] Serverless STNS

2021/12/25に公開

以下の25日目のエントリです。

STNS という rsa key pair で Linux ユーザーの SSH ログインを管理・制御できる素敵な OSS があります。
https://github.com/STNS/STNS
縁あって自分は 2016 年頃にこれを知り、とあるビッグプロジェクトでの利用を賛同・推進しました[3]。当時は 100 台超のサーバーにSTNSクライアントをインストールするなりテンプレート的な VM をクローンするなりして運用してました。サーバー側は config ファイルを手動調整でした。

時は 2021 年。サーバーはなるべく運用しない、SSH で入ったら負け、パスワードやめましょう、といった感じの流れの中でも、AWS ならセッションマネージャでいいじゃないか、GCP なら IAP[4] で行けるじゃないか、となった最近でも、全部IAMユーザー発行するの辛いわ・・・とか組織外で業務委託の人もいるんよね・・・的なユースケースはたぶんまだまだあり、そういった部分ではこの記事で紹介する Serverless STNS が秘蔵の便利さを発揮できると思います。

良さそう、と思ったら利用を検討してみていただければ幸いです。(ただし、ちゃんとメンテナンスできてないところがありそのへんはごめんなさいとしか言えないです)

夏場の調査を振り返る

「記事にする」詐欺がとうとう今まで続いてしまったのですが、2021年夏時点の最新情報での試行を書き連ねた Scrap がこちらになります。

https://zenn.dev/sogaoh/scraps/a089fb046eb747

時系列をざっと並べてみますと、以下のようになってます。

この記事では、ここまでを整理して使い方を記述します。

サーバーサイド(stns-backend)のセットアップ

READMEを書き上げてないのですが、リポジトリはこちらになります。
https://github.com/ant-in-giant/serverless-stns

module/aws-serverless-stns-api ディレクトリに上述の fork リポジトリを押し込めて、
stns-backend/create ディレクトリで terraform.tfvars を準備し、terraform init -> terraform plan -> terraform apply を行っていけばサーバーサイドが出来上がってくれるはずです。
実行の前提は こちらの Requirements / Setup を満たしていること[6]、で、 terraform.tfvars に必要な事項は以下になります。4行だけです。

stns-backend/create/terraform.tfvars 記述イメージ

profile = "default"
region = "ap-northeast-1"
aws_access_key = "AXXXXXXXXXXXXXXXXXXX"
aws_secret_key = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"

terraform apply が完了すると、以下のリソースが作られているはずです。

  • Lambda 関数
    • stns-api : STNS バックエンド
    • stns-authorizer : STNS カスタム認証機構
  • API Gateway
    • stns-api : STNS API (要求されたユーザー/グループの公開鍵等の情報を返す)
  • DynamoDB
    • stns-users テーブル : ユーザー情報
    • stns-groups テーブル : グループ情報
    • stns-authorizations テーブル : カスタム認証情報
  • CloudWatch Log Group
    • /aws/lambda/stns-api グループ : API呼び出しのログ。誰がログインを試みたかがわかる
    • /aws/lambda/stns-api-authorizer グループ : どのカスタム認証情報がリクエストされたかがわかる(どのサーバーにログインしようとしたのか)

ユーザー/グループデータの投入

すみませんこれはスクリプト等を用意していないので、自分はCLIで投入しました。(誰かにツールつくってほしい・・・という心境はあります・・・)
トークンの長さやグループ名はセンスが求められる等ありますが、設定の際にはLinuxの制約等にお気をつけください(2バイト文字とか使わないでくださいね、など)。

データ投入コマンド 実行例
❯ aws --profile default dynamodb put-item \
  --table-name "stns-authorizations" \
    --item '{
        "token": {"S": "TTTTTTTTTTTTTTTTTTTT"},
        "description": {"S": "全てのユーザーに認証を許可するトークン"},
        "groups": {"L": []},
        "users": {"L": []}
    }'
❯ aws --profile default dynamodb put-item \
    --table-name "stns-users" \
    --item '{
        "name": {"S": "sogaoh"},
        "id": {"S": "2001"},
        "group_id": {"S": "2001"},
        "shell": {"S": "/bin/bash"},
        "directory": {"S": "/home/sogaoh"},
        "keys": {"L": [ { "S": "ssh-rsa ........."} ]},
        "link_users": {"L": [] }
    }'
❯ aws --profile default dynamodb put-item \
    --table-name "stns-groups" \
    --item '{
        "name": {"S": "devops"},
        "id": {"S": "2001"},
        "users": {"L": [ {"S": "sogaoh"} ]},
        "link_groups": {"L": [] }
    }'

STNS API 単体の検証

STNS API 単体検証例
curl -H 'Authorization: token TTTTTTTTTTTTTTTTTTTT' \
  https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/v2/users
[{"name":"sogaoh","id":2001,"password":"","directory":"/home/sogaoh","shell":"/bin/bash","gecos":"","keys":["ssh-rsa ........."}group_id":2001}]

その他備考

  • Rubyのバージョンを最新化する際には anyenv上のrbenvでRubyのバージョンを最新化する - Qiita を参照しました。
  • ローカルの docker-compose で module/aws-serverless-stns-api を動かすことに成功できていません(Ruby力が足りない)
  • ほぼないかなと思いますが、サーバー側のプログラムを更新する際には lambroll を利用することができるようにしています。更新用スクリプト一式を stns-backend/lambroll に準備してありますが、.envrc や tfstate の場所( Makefile 中の OPT_TFSTATE )は適宜調整してください。

クライアントサイド(stns-client)のセットアップ

最初はサーバーサイドとまとめてこそ、と思っていたのですが、結局のところ分けています。
サーバーサイドのソースからはサブモジュールで紐付けています。クライアントセットアップなんだから、クライアント用のセットアップ一式だけでいいよね、という判断で分けました。
https://github.com/ant-in-giant/stns-client-setup

こちらも README が書けていませんが、セットアップしたサーバーの output、つまり API のエンドポイントURLと、自身で設定するであろうカスタム認証トークンを、variables.yaml.example に倣って clone した直下に variables.yaml として保存し、make stns を実行すればセットアップされる想定です。(make dry-stns は適宜)

variables.yaml 記述イメージ
api_end_point: https://stns-api-id.execute-api.ap-northeast-1.amazonaws.com/v2
auth_token: oreno-my-stns-token-001

実行の前提ですが、Ansible のインストールくらいかなとは思いますが Python 2 系と 3 系の共存が必要かもしれません。。最近のアップグレードが著しく、と思っているのと8月以来まともに検証できてないので少し心配ではあります。
それと、対応OSは今のところ Amazon Linux 2 と Ubuntu 20.04 のみです。そして AWS 限定です。
他の OS or AWS以外の場合は以下のガイドに準じて手動で行うのが妥当かもしれません。
https://stns.jp/ja/install

クライアントからの STNS サーバーへの接続検証

セットアップができたら、クライアント側からの鍵取得を検証しておくとベターかと思います。
方法は、OS別になりますが roles/stns-client/templates/usr/local/bin 配下のラッパースクリプトに記述してあるコマンドを鍵を登録したユーザー名をパラメータにして呼び出す、でOKだったと思います。

  • AWS Amazon Linux 2 or Ubuntu 20.04
    • /usr/lib/stns/stns-key-wrapper ${USER}

サーバー・クライアントともにここまで検証ができたら、いよいよ STNS でログインできるかに Try です。
うまくいけばこんな感じでログインできて、初回であればホームディレクトリが自動作成されると思います。

STNS ログイン 成功例(.ssh/config で 接続設定済み、という前提)
ssh stns-focal
The authenticity of host 'XX.XXX.XXX.XXX (XX.XXX.XXX.XXX)' can't be established.
ECDSA key fingerprint is SHA256:KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'XX.XXX.XXX.XXX' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.11.0-1016-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sat Dec 25 04:59:15 UTC 2021

  System load:  0.12              Processes:             112
  Usage of /:   25.2% of 7.69GB   Users logged in:       0
  Memory usage: 49%               IPv4 address for ens5: 172.31.35.58
  Swap usage:   0%


5 updates can be applied immediately.
4 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: WWW XXX 31 20:05:06 2021 from YY.YYY.YYY.YY
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

sogaoh@ip-172-31-35-58:~$

Mackerel で Serverless STNS を監視

おまけ的な節です。
READMEがそれなりにちゃんと書けているので、せっかくなので置いておこう、と思い。
https://github.com/sogaoh/mackerel-practice/tree/master/terraform-provider/serverless-stns

そして、自分のは1人だけなので面白そうな分析も何もできないと思うのですが、それなりの規模のチームでSTNSを運用する場合、最近出てきた mackerel-monitoring-modules/cloudwatch-logs-aggregator が活用できるかもしれないな、とこの記事を書きながら思いました。

cloudwatch-logs-aggregator の紹介ブログはこちら↓
https://susisu.hatenablog.com/entry/2021/12/15/012729

さいごに

今年のアドベントカレンダーは今日で終了ですが来年も秘蔵の投稿をやっていければなあ、と思います。
なお昨日、1つ予定ネタが生まれました。カレンダー立ち上げるかどうかはわかりませんが。1年あればいろんな方にいろんな出来事があるかなあと。

https://twitter.com/sogaoh/status/1474218225110233091

脚注
  1. 24日目は merutin さんの「AppSyncで何か」の予定です(12/25 15:00時点で未投稿)。 ↩︎

  2. 24日目は GOETAN さんの「フレッツ光の導入珍事件」の予定です(12/25 15:00時点で未投稿)。 ↩︎

  3. 現在はどうなってるかわからないのですが pg_repackでテーブルスペースを移動して容量の危機を脱した2018.5.23 をやったプロジェクト ↩︎

  4. Identity-Aware Proxy。refs https://cloud.google.com/iap ↩︎

  5. https://github.com/STNS/stns-playbook など ↩︎

  6. md5sum コマンド が必要と書いてありますが、これは不要そうです。https://github.com/ant-in-giant/serverless-stns を整備している段階でわかりました。 ↩︎

Discussion