はじめに
内部開発者ポータルとしてその名前を聞くことが多くなった Backstage ですが、その特徴の1つが、それぞれの組織で必要となる機能をPluginという形で拡張できることです。そしてPlugin間や外部サービスとの間で通信連携することでそれぞれの機能をより高めています。
Backstageそのものは Modular Monolith/Microservice アーキテクチャーを採用しており、機能拡張のPluginがBackstageとは独立したプロセスとして実行することもできます。ネットワーク越しのPlugin間(または外部サービスとPlugin間)通信を行う場合にセキュリティ上重要になってくるのがサービス間認証です。サービス間認証で通信相手が正しい相手か(第3者からの不適正な通信ではないか)を確認します。
Backstageもサービス間認証の仕組みを持っていますが、実はBackstage v1.24.0からその方式に変更がありました。今回は新旧のBackstageのサービス間認証についてご紹介したいと思います。
サービス間認証概要
BackstageではBackstage本体(基本サービス)やPlugin、外部サービス、TechDocsなどのBackstage CLIとの間でhttpプロトコルを用いた通信を行います。これがサービス間通信です。
サービス間認証を行う場合は、これらの通信のAuhtorizationヘッダにトークンを付加し、そのトークンをチェックすることで実現します。この概要レベルでのサービス間認証は新旧Backstageで違いはありません。
旧方式
旧方式のサービス間認証ではJWT形式のトークンを採用しています。 Backstage本体やPluginでは 、Backstageのapp-config.yamlに指定されたシークレットを元にトークンを生成します。
# commonly in your app-config.production.yaml backend: auth: keys: - secret: <the string returned by the above crypto command> # - secret: ${BACKEND_SECRET} - if you want to use an env variable instead
トークンの生成はBackstageで用意されているTokenManagerを利用し、Authorizationヘッダに記述すれば通信できます。
外部サービスの場合はBackstageのTokenManagerを使うことができません。このため開発者自身でJWTトークンを生成します。 その際、subとexpを以下のように設定します
- HS256 signature
- BASE64でencodeした文字列をsecretとして利用
- sub:
backstage-server
という文字列(固定) - exp: 1時間の有効期限
外部サービスと通信する対象のBackstageでsecret文字列を共有することで、受信側でJWTの内容を確認できるようにします。
end: auth: keys: - secret: my-secret-key-1 - secret: my-secret-key-2 - secret: my-secret-key-3
my-secret-key-1
はBackstage本体で使用するキーであるため、一般的には my-secret-key-2
や my-secret-key-3
を外部サービスごとに用意してそれらを外部サービスと共有して使用します。
旧方式ではデフォルトでは無効だった
旧システムでは1つ注意事項があります。
以前以下のような内容を紹介させていただきましたように実はv.124以前の旧バージョンサービス間認証はデフォルトではオフになっており、認証を利用する場合は明示的に有効にする必要がありました。
Pluginを独立したプロセスで実行する方法も用意されてはいましたが多くは同一プロセス内で実行することが多かったことがデフォルトでオフだった理由かもしれません。
旧方式ではまずサービス間認証を有効にしましょう。
新方式
新方式のサービス間認証では旧システムで利用されていたJWT方式(legacy
と呼んでいます)に加え、外部システム用に用意された単純文字列方式(static
と呼んでいます)が追加されました。
static方式はトークンとして app-config.yamlで指定した文字列をそのまま Authorization Headerに指定することができます。
static方式でtokenは最低でも8文字以上で、空白を含むことはできません 。 subjectは空白を含まない文字列としてください。内部でJSONオブジェクトのキーとして利用しているので、英数字や-_といった文字を利用しておくとよいと思います。
旧システムでご紹介したとおり従来はトークンはJWT形式にしなければなりません。JWT形式を生成可能なプログラムから通信を行う場合は問題ないのですが、コマンドラインツールなどから利用する場合には不都合です。こうした場合には新しい static
方式を利用して簡素に実現できるようしています。
新方式と旧方式を区別できるようにするため、app-config.yamlでの指定が backend.auth.keys
から backend.auth.externalAccess
に変更されています。
backend: auth: externalAccess: - type: legacy options: secret: my-secret-key-catalog subject: backstage-server - type: static options: token: ${CICD_TOKEN} subject: cicd-system-completion-events
なお、Backstageで利用されるサービス間認証は legacy
のJWT方式です。このため、backend.auth.externalAccessには必ず1つ legacy
を登録する必要があります。
また、旧方式の backend.auth.keys
でも問題なく動作しますが、v1.26で実行した際の起動時ログに backend.auth.keys
はDEPRECATEDですというワーニングが表示されるので、新しい backend.auth.externalAccess
に記載を変更したほうがよいでしょう。
旧方式はすべて legacy
ですので、旧方式で紹介したものは以下のような内容に書き換えればOKです。
backend: auth: externalAccess: - type: legacy options: secret: my-secret-key-1 subject: backstage-server - type: legacy options: secret: my-secret-key-2 subject: cicd - type: legacy options: secret: my-secret-key-3 subject: external-server
最後に
Backstageがv1.24から新Backend Systemにシフトしさらに進化を遂げていく中で、いくつかの部分で新しい機構が組み込まれています。今回紹介したサービス間認証方式もそうした新しい機構の1つです。新しい機構が出るのはよいのですが、旧方式から新方式にマイグレーションする方法など、1つ1つ調べなければならないのが少し手間です。 今回の情報が皆様の「手間」と感じる部分の解消になれば幸いです。
お知らせ
2024年7月9日に Platform Engineering KAIGI 2024 というイベントが開催されます。 私自身はセッションなどの応募などはしていませんが、一般参加者のひとりとして現地に参加したいと考えています。 懇親会もあるようなので、そうした場で皆様とBackstageやPlatform Engineering、システム開発についてお話をさせていただけると幸いです。
弊社では「プラットフォームエンジニアリング推進支援」も行っています。
Backstageを内部開発者ポータルとして導入するなどの支援も行っています。「Platform Engineeringはじめたいのだけど」「Backstageって興味ある、導入したい」などありましたらぜひご相談ください。