[Day.25] Serverless STNS
以下の25日目のエントリです。
- AWS LambdaとServerless Advent Calendar 2021 [1]
- corp-engr 情シスSlack(コーポレートエンジニア x 情シス)#2 Advent Calendar 2021 [2]
STNS という rsa key pair で Linux ユーザーの SSH ログインを管理・制御できる素敵な OSS があります。[3]。当時は 100 台超のサーバーにSTNSクライアントをインストールするなりテンプレート的な VM をクローンするなりして運用してました。サーバー側は config ファイルを手動調整でした。
縁あって自分は 2016 年頃にこれを知り、とあるビッグプロジェクトでの利用を賛同・推進しました時は 2021 年。サーバーはなるべく運用しない、SSH で入ったら負け、パスワードやめましょう、といった感じの流れの中でも、AWS ならセッションマネージャでいいじゃないか、GCP なら IAP[4] で行けるじゃないか、となった最近でも、全部IAMユーザー発行するの辛いわ・・・とか組織外で業務委託の人もいるんよね・・・的なユースケースはたぶんまだまだあり、そういった部分ではこの記事で紹介する Serverless STNS が秘蔵の便利さを発揮できると思います。
良さそう、と思ったら利用を検討してみていただければ幸いです。(ただし、ちゃんとメンテナンスできてないところがありそのへんはごめんなさいとしか言えないです)
夏場の調査を振り返る
「記事にする」詐欺がとうとう今まで続いてしまったのですが、2021年夏時点の最新情報での試行を書き連ねた Scrap がこちらになります。
時系列をざっと並べてみますと、以下のようになってます。
- オリジナルは @ryoryoryohei さんの サーバーレスでプライベートな STNS のバックエンド API を AWS で実現した話 (2019年2月)
- それを Ruby と Terraform バージョンアップなどして Deploy 成功できたのが こちらの fork リポジトリ。README がアップデートしてあります。(2021年8月)
- クライアントセットアップの簡素化を試みたと思われるリポジトリが複数見つかるものの[5]、どうやらパブリックな状態なのはなさそうに感じて「それなら俺が」とやり出す。
- CentOS では成功したが Amazon Linux WorkSpaces では認証機構の違いから不首尾に終わる。過程で EC2 Instance Connect を知るなど。
- その後 Ubuntu (20.04) でもクライアントセットアップに成功。
この記事では、ここまでを整理して使い方を記述します。
サーバーサイド(stns-backend)のセットアップ
READMEを書き上げてないのですが、リポジトリはこちらになります。
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)のセットアップ
最初はサーバーサイドとまとめてこそ、と思っていたのですが、結局のところ分けています。
サーバーサイドのソースからはサブモジュールで紐付けています。クライアントセットアップなんだから、クライアント用のセットアップ一式だけでいいよね、という判断で分けました。
こちらも 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以外の場合は以下のガイドに準じて手動で行うのが妥当かもしれません。
クライアントからの 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がそれなりにちゃんと書けているので、せっかくなので置いておこう、と思い。
そして、自分のは1人だけなので面白そうな分析も何もできないと思うのですが、それなりの規模のチームでSTNSを運用する場合、最近出てきた mackerel-monitoring-modules/cloudwatch-logs-aggregator が活用できるかもしれないな、とこの記事を書きながら思いました。
cloudwatch-logs-aggregator の紹介ブログはこちら↓
さいごに
今年のアドベントカレンダーは今日で終了ですが来年も秘蔵の投稿をやっていければなあ、と思います。
なお昨日、1つ予定ネタが生まれました。カレンダー立ち上げるかどうかはわかりませんが。1年あればいろんな方にいろんな出来事があるかなあと。
-
現在はどうなってるかわからないのですが pg_repackでテーブルスペースを移動して容量の危機を脱した2018.5.23 をやったプロジェクト ↩︎
-
Identity-Aware Proxy。refs https://cloud.google.com/iap ↩︎
-
md5sum コマンド が必要と書いてありますが、これは不要そうです。https://github.com/ant-in-giant/serverless-stns を整備している段階でわかりました。 ↩︎
Discussion