Credential Composer pluginとは
SPIRE Serverが発行するX509-SVID, JWT-SVIDのフィールドをカスタマイズすることができるpluginです。
これまでも、Workload X509-SVIDのSubjectのCN
やDNS SAN
についてはRegistration Entryにて-dns
で値をセットすることで任意の値を設定することができましたが、Credential Composer pluginではWorkload X509-SVIDに対する他の属性だけでなく、Server X509-SVID、Agent X509-SVID、X509CA-SVIDといった他のSVIDの属性もカスタマイズ可能になります。
例えば X509 SVIDであればSubjectのDN
全体やDNS SAN
、他のX.509 Extensions
(OIDを指定)などがカスタマイズ可能です。
message ComposeWorkloadX509SVIDResponse {
// The attributes for the workload X509-SVID. To maintain forward
// compatibility with future attribute field additions, these attributes
// SHOULD be populated with the mutated attributes field in the
// ComposeWorkloadX509SVIDRequest. If this message is not included in the
// response, the original attributes sent in the request will be used.
X509SVIDAttributes attributes = 1;
}
message X509SVIDAttributes {
// The subject of the X509-SVID.
DistinguishedName subject = 1;
// Zero or more DNS SANs to apply to the X509-SVID.
repeated string dns_sans = 2;
// Zero or more extensions to apply to the X509-SVID . These will override
// any extensions otherwise added by the other fields. This field cannot
// be used to change the URI SAN of the X509-SVID (i.e. the SPIFFE ID).
repeated X509Extension extra_extensions = 3;
}
Pluginでカスタマイズ可能なSVIDタイプ毎のフィールドや詳細は以下のprotoファイルを参照してください。
SPIREのCAはSVID生成前にCredential Composer pluginを呼び出し(設定されていれば)、カスタマイズされた値を受け取ります。現在の実装では、Pluginはデフォルト値を利用する場合はリクエストパラメータとしてデフォルト値が渡されるのでPlugin側でマージが必要そうです。また、Credential Composer pluginは複数設定できるようですが、上書きされるため同じフィールド(attributes)をカスタマイズする場合は注意が必要そうです。
e.g. external pluginとして実装された場合
なぜ必要となったのか
Subjectに関していえば、現在ではSANが利用されるようになっていることや、SPIFFEの世界ではURI SANにセットされているSPIFEFE ID
を識別子とするため、当初はそれほどカスタマイズが必要と考えられていなかったように思います。
しかし、現実では様々な実装があり、SPIREがリリースされてからこれまでにSVIDのフィールドをカスタマイズしたいという要望が多くありました。例えば X509-SVIDのSubjectをユニークなものにしたいや、CNにSPIFFE IDをセットしたいなど。
これらの要望に対して柔軟に対応するための手段としてフィールドをカスタマイズ可能なpluginが提供されることになりました。
Plugins
Buit-in
Credential Composer pluginにはビルトインされたものはありません。
External
GitHubのパブリックリポジトリを検索してみましたが、公開されているExtenalプラグインは見つかりませんでした。
spire-plugin-sdkでインタフェースが公開されています。それを使った実装のテンプレート も公開されているため、必要な機能をプラグインとしてSPIREリポジトリとは別に実装することができます。
この場合SPIREとは別のバイナリとしてインストールしてSPIRE ServerからPluginとして起動してもらいます。詳細はリポジトリを参照してください。
Examples
Plugin コード
credentialcomposer.go
(spire-plugin-sdkリポジトリのtemplateをコピー)
package main
...省略...
type Config struct {
Country string `hcl:"country"`
Organization string `hcl:"organization"`
CommonName string `hcl:"common_name"`
}
...省略...
func (p *Plugin) ComposeWorkloadX509SVID(ctx context.Context, req *credentialcomposerv1.ComposeWorkloadX509SVIDRequest) (*credentialcomposerv1.ComposeWorkloadX509SVIDResponse, error) {
config, err := p.getConfig()
if err != nil {
return nil, err
}
return &credentialcomposerv1.ComposeWorkloadX509SVIDResponse{
Attributes: &credentialcomposerv1.X509SVIDAttributes{
Subject: &credentialcomposerv1.DistinguishedName{
Country: []string{config.Country},
Organization: []string{config.Organization},
CommonName: config.CommonName,
},
},
}, nil
}
...省略...
これを適当にビルドしてSPIRE Serverのバイナリと同じノードに配置します。
今回の設定では /tmp
配下にmy-credential-composer
として配置しました。
Server 設定ファイル
server.conf
server {
bind_address = "127.0.0.1"
bind_port = "8081"
socket_path = "/tmp/spire-server/private/api.sock"
trust_domain = "example.org"
data_dir = "./.data"
log_level = "DEBUG"
}
plugins {
DataStore "sql" {
plugin_data {
database_type = "sqlite3"
connection_string = "./.data/datastore.sqlite3"
}
}
NodeAttestor "join_token" {
plugin_data {
}
}
KeyManager "memory" {
plugin_data = {}
}
UpstreamAuthority "disk" {
plugin_data {
key_file_path = "./conf/server/dummy_upstream_ca.key"
cert_file_path = "./conf/server/dummy_upstream_ca.crt"
}
}
CredentialComposer "my-composer" {
plugin_cmd = "/tmp/my-credential-composer"
plugin_data {
country = "JP"
organization = "Z Lab Corporation"
common_name = "my-workload.example.org"
}
}
}
配置したExternal pluginを参照するようにCredentialComposer pluginの設定を追加します。
動作確認
SPIRE Serverを起動します。
# ./spire-server run -config conf/server/server.conf
SPIRE AgentのNode Attestation用Tokenを発行します。
# ./spire-server token generate -spiffeID spiffe://example.org/token
Token: xxx
Workload用のRegistration Entryを作成します。
# ./spire-server entry create -parentID spiffe://example.org/token -spiffeID spiffe://example.org/workload -selector unix:uid:0
Entry ID : 35d7a63c-b67a-43db-9933-01336d371772
SPIFFE ID : spiffe://example.org/workload
Parent ID : spiffe://example.org/token
Revision : 0
X509-SVID TTL : default
JWT-SVID TTL : default
Selector : unix:uid:0
SPIRE Agentを起動します。Agentの設定は設定例をそのまま利用しています。
# ./spire-agent run -config conf/agent/agent.conf -joinToken xxx
Workload X509-SVIDを取得します。SPIRE AgentのCLIを使って取得します。uid=0
に対するEntryを作成しているためルートで取得しています。
# ./bin/spire-agent api fetch x509 -write .
SPIFFE ID: spiffe://example.org/workload
SVID Valid After: 2023-11-30 01:23:20 +0000 UTC
SVID Valid Until: 2023-11-30 02:23:30 +0000 UTC
Intermediate #1 Valid After: 2023-11-30 01:21:59 +0000 UTC
Intermediate #1 Valid Until: 2023-12-01 01:22:09 +0000 UTC
CA #1 Valid After: 2023-05-15 02:05:06 +0000 UTC
CA #1 Valid Until: 2028-05-13 02:05:06 +0000 UTC
X509-SVIDのSubjectを見てみます。
# openssl x509 -in svid.0.pem -noout -subject
subject= /C=JP/O=Z Lab Corporation/CN=my-workload.example.org
テスト用のプラグインに対して設定した値と同じものが入っていることが確認できました。
Agent SVIDのカスタマイズは実装していないのでデフォルト値のままです。
# openssl x509 -inform DER -in .data/agent_svid.der -noout -subject
subject= /C=US/O=SPIRE/x500UniqueIdentifier=07c74a3d23b588f875d23ee96e070217
まとめ
Credential Composer pluginを実装することで簡単にSVIDの属性パラメータをカスタマイズできることがわかりました。
システムのアクセス制御にRBACのような仕組みを使っており、X.509証明書のSubjectの値を参照して制御しているような環境へのSVIDの適用など、利用範囲がより広がりそうです。
Links
Issues