3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UpstreamAuthority spire pluginを使ってNested SPIREを構成する

Last updated at Posted at 2020-12-14

昨日のエントリでは**、UpstreamCA** pluginには複数台でSPIRE Serverを構成したときにJWT SVIDを正しく扱えないことあったという話と、それを解決するためにUpstreamAuthority pluginが登場した話をしました。
本日は実際にUpstreamAuthority spire pluginを使って、複数台でSPIRE Serverを構成した場合にもJWT SVIDの検証鍵がワークロードに正しく配布されることを確認します。

Nested SPIREとは

UpstreamAuthority spire pluginでは、Upstream AuthorityとなるUpstreamのSPIREとそれを参照するDownstreamのSPIREによる多段の構成となり、SPIREプロジェクトではこれをNested SPIREと呼んでいます。
DownstreamのSPIRE Serverは、UpstreamのSPIRE ServerにX.509 SVIDのCA証明書発行の依頼やJWTの検証鍵を登録したりします。UpstreamのSPIRE Serverはさらに外部のCAと接続してもよいですし、自身がルートCAとなってもよいです。

Nested SPIREを構成するにあたって必要となる、Downstream SPIRE ServerのためのCA証明書発行のエンドポイントは認証・認可によるアクセス制御がおこなわれています。SPIRE Serverはリクエスト元のSPIFFE IDに対して、自身がもつRegistrationEntryで対象SPIFFE IDのエントリにdownstreamのフラグが立っていることを確認します。
したがって、Nested SPIRE構成では、UpstreamのSPIRE ServerにDownstream SPIREのためのRegistrationEntryの登録が必要になり、DownstreamのSPIRE ServerはそのSPIFFE IDを含むSVIDをUpstreamのSPIREから取得し、それを使ってCA証明書発行用のエンドポイントに接続しなければなりません。

e.g. downstream フラグが立っているRegistrationEntryの例

Entry ID      : e79c6ae1-186f-4430-ad2d-dfe33bdacd3f
SPIFFE ID     : spiffe://example.org/my-downstream-spire
Parent ID     : spiffe://example.org/my-node
Revision      : 0
Downstream    : true
TTL           : default
Selector      : unix:uid:0

そのため、UpstreamAuthority spire pluginでは、DownstreamのSPIRE ServerのノードにSPIRE Agentを同居させ、Downstream SPIRE ServerはAgentが提供するWorkload API経由でUpstream SPIREが署名したSVIDを取得し、これを使ってUpstream SPIRE Serverに接続するような方法を取っています。

Upstream SPIRE Serverのセットアップ

設定ファイルは公式リポジトリで提供されている設定ファイル例を参考に以下のようにしています。

Upstream SPIRE Serverの設定

Upstream SPIRE ServerはUpstreamAuthority disk pluginを使っており、今回の設定ではこのファイルで配置されたCA証明書がルートCAの証明書となります。disk pluginは、ファイルとして配置された秘密鍵を使ってUpstream SPIRE ServerのCA証明書を発行します。
NodeAttestationについては、プラットフォームに依存しないpluginとして join_token, x509pop, sshpopの3つがビルトインとして提供されています。ここでは一番簡単なJoin Tokenというワンタイムトークンを使ったjoin_tokenpluginを使ってセットアップします。

**x509pop**, **sshpop**を使ったNode Attestationについては、明日のエントリで紹介したいと思います。

server {
    bind_address = "0.0.0.0"
    bind_port = "8081"
    registration_uds_path = "/tmp/spire-registration.sock"
    trust_domain = "example.org"
    data_dir = "/var/lib/spire/data"
    log_level = "DEBUG"
    default_svid_ttl = "1h"
    ca_subject = {
        country = ["US"]
        organization = ["SPIFFE"]
        common_name = ""
    }
}

plugins {
    DataStore "sql" {
        plugin_data {
            database_type = "sqlite3"
            connection_string = "/var/lib/spire/data/datastore.sqlite3"
        }
    }

    NodeAttestor "join_token" {
        plugin_data {
        }
    }

    NodeResolver "noop" {
        plugin_data {}
    }

    KeyManager "memory" {
        plugin_data = {}
    }

    UpstreamAuthority "disk" {
        plugin_data {
            key_file_path = "/var/lib/spire/ca/dummy_upstream_ca.key"
            cert_file_path = "/var/lib/spire/ca/dummy_upstream_ca.crt"
        }
    }
}

Upstream SPIRE Serverの起動

upstream-spire-0 $ spire-server run -config server.conf

Upstream SPIRE ServerにてJoin Tokenの発行

DownstreamのSPIRE Agentが接続するためのワンタイムトークンを発行します。

upstream-spire-0 $ sudo spire-server token generate \
-spiffeID spiffe://example.org/nodes/downstream-spire

Token: <Token String...> 

Upstream SPIRE ServerでのJWT検証鍵一覧

以下のコマンドでSPIRE Serverが持っているJWT検証鍵を確認することができます(usejwt-svidになっているもの)。
この時点ではUpstream SPIRE Server一台しか存在しないため、検証鍵も当然一つしか表示されていません。

upstream-spire-0 $ sudo spire-server experimental bundle show
{
    "keys": [
        {
            "use": "x509-svid",
            "kty": "EC",
            "crv": "P-384",
            "x": "WjB-nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0",
            "y": "Z-0_tDH_r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs_mcmvPqVK9j",
            "x5c": [
                "MIIBzDCCAVOgAwIBAgIJAJM4DhRH0vmuMAoGCCqGSM49BAMEMB4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMTgwNTEzMTkzMzQ3WhcNMjMwNTEyMTkzMzQ3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWjB+nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0Z+0/tDH/r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs/mcmvPqVK9jo10wWzAdBgNVHQ4EFgQUh6XzV6LwNazA+GTEVOdu07o5yOgwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwGQYDVR0RBBIwEIYOc3BpZmZlOi8vbG9jYWwwCgYIKoZIzj0EAwQDZwAwZAIwE4Me13qMC9i6Fkx0h26y09QZIbuRqA9puLg9AeeAAyo5tBzRl1YL0KNEp02VKSYJAjBdeJvqjJ9wW55OGj1JQwDFD7kWeEB6oMlwPbI/5hEY3azJi16I0uN1JSYTSWGSqWc="
            ]
        },
        {
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
            "crv": "P-256",
            "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
            "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
        }
    ]
}

Upstream SPIRE ServerにてRegistrationEntryの作成

Join Token発行時に指定したSPIFFE IDをParent IDとして指定し、Downstream SPIRE Serverに対応するRegistrationEntryのレコードを作成します。

upstream-spire-0 $ sudo spire-server entry create 
-parentID spiffe://example.org/nodes/downstream-spire 
-spiffeID spiffe://example.org/workloads/downstream-spire 
-selector unix:uid:0
-downstream

Entry ID      : 20029c0e-f4b1-42df-af1e-fcd75609c631
SPIFFE ID     : spiffe://example.org/workloads/downstream-spire
Parent ID     : spiffe://example.org/nodes/downstream-spire
Downstream    : true
TTL           : 3600
Selector      : unix:uid:0

Downstream SPIRE Agentの設定

Downstream SPIRE Agentはserver_addressにUpstream SPIRE ServerのIPアドレスやFQDNを指定します。また、Node Attestationに必要なJoin Tokenは起動パラメータまたは、設定ファイルで指定する必要があり、今回は設定ファイル内で指定しています。

agent {
    data_dir = "/var/lib/spire/data"
    log_level = "DEBUG"
    server_address = "${UPSTREAM_SPIRE_ADDR}"
    server_port = "8081"
    socket_path ="/tmp/agent.sock"
    # upstream spire serverで指定したUpstream CAの証明書
    trust_bundle_path = "/etc/spire/dummy_upstream_ca.crt"
    trust_domain = "example.org"
    # upstream spire serverで発行したトークン
    join_token = "${JOIN_TOKEN}"
}

plugins {
    NodeAttestor "join_token" {
        plugin_data {
        }
    }
    # 再起動のたびにトークン再発行にならないように今回は秘密鍵をdiskに保管 
    KeyManager "disk" {
        plugin_data {
            directory = "/var/lib/spire/data/key"
        }
    }
    # 今回は単純にするためunix pluginのみ
    WorkloadAttestor "unix" {
        plugin_data {
        }
    }
}

Downstream SPIRE Agentの起動

downstream-spire-0 $ sudo spire-agent run -config agent.conf

Downstream SPIRE Serverの設定

Downstream SPIRE ServerではUpstreamAuthority spire pluginを利用し、pluginの設定にてUpstream SPIRE Serverのアドレスを指定しています。

※ Downstream SPIRE Serverはスケールアップなどの要件で複数台で構成されることが予想されるため、本来はデータストアとしてMySQLなどを選択し複数のDownstream SPIRE Serverでデータストアを共有する構成にする必要があります。今回はJWTの検証鍵の配布の確認だけが目的なのでローカルのデータストアを参照しています。

参考: https://github.com/spiffe/spire/blob/master/doc/scaling_spire.md#spire-servers-in-high-availability-mode

server {
    bind_address = "0.0.0.0"
    bind_port = "8081"
    registration_uds_path = "/tmp/spire-registration.sock"
    trust_domain = "example.org"
    data_dir = "/var/lib/spire/data"
    log_level = "DEBUG"
    default_svid_ttl = "1h"
    ca_subject = {
        country = ["US"]
        organization = ["SPIFFE"]
        common_name = ""
    }
}

plugins {
    DataStore "sql" {
        plugin_data {
            # 本来は複数台で構成する場合はMySQLなどを利用する
            database_type = "sqlite3"
            connection_string = "/var/lib/spire/data/datastore.sqlite3"
        }
    }
 
    NodeAttestor "join_token" {
        plugin_data {
        }
    }

    NodeResolver "noop" {
        plugin_data {}
    }

    KeyManager "memory" {
        plugin_data = {}
    }

    UpstreamAuthority "spire" {
        plugin_data {
            server_address = "${UPSTREAM_SPIRE_ADDR}",
            server_port = "8081",
            workload_api_socket = "/tmp/agent.sock"
        }
    }
}

Downstream SPIRE Serverの起動

downstream-spire-0 $ spire-server run -config server.conf

JWT検証鍵の確認

Upstream SPIRE Serverにて先ほどと同じコマンドを実行してみると、JWT検証鍵が一つ増えていることが確認できます。

upstream spire server

upstream-spire-0 $ sudo spire-server experimental bundle show
{
    "keys": [
        {
            "use": "x509-svid",
            "kty": "EC",
            "crv": "P-384",
            "x": "WjB-nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0",
            "y": "Z-0_tDH_r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs_mcmvPqVK9j",
            "x5c": [
                "MIIBzDCCAVOgAwIBAgIJAJM4DhRH0vmuMAoGCCqGSM49BAMEMB4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMTgwNTEzMTkzMzQ3WhcNMjMwNTEyMTkzMzQ3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWjB+nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0Z+0/tDH/r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs/mcmvPqVK9jo10wWzAdBgNVHQ4EFgQUh6XzV6LwNazA+GTEVOdu07o5yOgwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwGQYDVR0RBBIwEIYOc3BpZmZlOi8vbG9jYWwwCgYIKoZIzj0EAwQDZwAwZAIwE4Me13qMC9i6Fkx0h26y09QZIbuRqA9puLg9AeeAAyo5tBzRl1YL0KNEp02VKSYJAjBdeJvqjJ9wW55OGj1JQwDFD7kWeEB6oMlwPbI/5hEY3azJi16I0uN1JSYTSWGSqWc="
            ]
        },
        { # upstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
            "crv": "P-256",
            "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
            "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
        },
        { # downstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "v7WFMeyjcmRi895PP0Kzis6iKVFcjrgt",
            "crv": "P-256",
            "x": "TTiFdYM2b2IZ0otfPD3oB14rULysd0PsQ-V3eZf56SM",
            "y": "cXFVTawAcfyv2sYD0vo3Nh0MLT7BdJ_bIXKR2z33YWM"
        }
    ]
}

さらにDownstream SPIRE Serverも同様に鍵が伝搬されていることを確認します。

downstream spire server

downstream-sprie-0 $ sudo spire-server experimental bundle show
{
    "keys": [
        {
            "use": "x509-svid",
            "kty": "EC",
            "crv": "P-384",
            "x": "WjB-nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0",
            "y": "Z-0_tDH_r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs_mcmvPqVK9j",
            "x5c": [
                "MIIBzDCCAVOgAwIBAgIJAJM4DhRH0vmuMAoGCCqGSM49BAMEMB4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMTgwNTEzMTkzMzQ3WhcNMjMwNTEyMTkzMzQ3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWjB+nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0Z+0/tDH/r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs/mcmvPqVK9jo10wWzAdBgNVHQ4EFgQUh6XzV6LwNazA+GTEVOdu07o5yOgwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwGQYDVR0RBBIwEIYOc3BpZmZlOi8vbG9jYWwwCgYIKoZIzj0EAwQDZwAwZAIwE4Me13qMC9i6Fkx0h26y09QZIbuRqA9puLg9AeeAAyo5tBzRl1YL0KNEp02VKSYJAjBdeJvqjJ9wW55OGj1JQwDFD7kWeEB6oMlwPbI/5hEY3azJi16I0uN1JSYTSWGSqWc="
            ]
        },
        { # upstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
            "crv": "P-256",
            "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
            "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
        },
        { # downstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "v7WFMeyjcmRi895PP0Kzis6iKVFcjrgt",
            "crv": "P-256",
            "x": "TTiFdYM2b2IZ0otfPD3oB14rULysd0PsQ-V3eZf56SM",
            "y": "cXFVTawAcfyv2sYD0vo3Nh0MLT7BdJ_bIXKR2z33YWM"
        }
    ]
}

Downstream SPIRE Serverの追加

ここでDownstream SPIRE Serverをもう一台追加してみます。
DownstreamのAgentとServerの設定は同じですが、Join Tokenは追加するNode用に発行する必要があります。

upstream-spire-0 $ sudo spire-server token generate \
-spiffeID spiffe://example.org/nodes/downstream-spire

Token: <Token String...> 


downstream-spire-1 $ spire-agent run -config agent.conf
downstream-spire-1 $ spire-server run -config server.conf

JWT検証鍵一覧の確認

Downstream SPRIE Serverを一台追加したところで、再度JWTの検証鍵を確認してみると、すべてのSPIRE Serverで検証鍵が一つ追加されていることが確認できます。

upstream-spire-0 $ sudo spire-server experimental bundle show
{
    "keys": [
        {
            "use": "x509-svid",
            "kty": "EC",
            "crv": "P-384",
            "x": "WjB-nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0",
            "y": "Z-0_tDH_r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs_mcmvPqVK9j",
            "x5c": [
                "MIIBzDCCAVOgAwIBAgIJAJM4DhRH0vmuMAoGCCqGSM49BAMEMB4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMTgwNTEzMTkzMzQ3WhcNMjMwNTEyMTkzMzQ3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWjB+nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0Z+0/tDH/r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs/mcmvPqVK9jo10wWzAdBgNVHQ4EFgQUh6XzV6LwNazA+GTEVOdu07o5yOgwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwGQYDVR0RBBIwEIYOc3BpZmZlOi8vbG9jYWwwCgYIKoZIzj0EAwQDZwAwZAIwE4Me13qMC9i6Fkx0h26y09QZIbuRqA9puLg9AeeAAyo5tBzRl1YL0KNEp02VKSYJAjBdeJvqjJ9wW55OGj1JQwDFD7kWeEB6oMlwPbI/5hEY3azJi16I0uN1JSYTSWGSqWc="
            ]
        },
        { # upstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
            "crv": "P-256",
            "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
            "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
        },
        { # downstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "v7WFMeyjcmRi895PP0Kzis6iKVFcjrgt",
            "crv": "P-256",
            "x": "TTiFdYM2b2IZ0otfPD3oB14rULysd0PsQ-V3eZf56SM",
            "y": "cXFVTawAcfyv2sYD0vo3Nh0MLT7BdJ_bIXKR2z33YWM"
        },
        { # downstream-spire-1の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "5rtNSCHGanu4zZxHEMElcD40EpEXWWBy",
            "crv": "P-256",
            "x": "JcAOx-y9l0irle-4dIn6XN7ei5Kxtq9TGlDNTyRpRec",
            "y": "At-3XXCrVs5OBiTKcwCIhA9lj_iGf05lWaOS6LxBo_4"
        }
    ]
}


downstream-spire-0 $ sudo spire-server experimental bundle show
{
    "keys": [
        {
            "use": "x509-svid",
            "kty": "EC",
            "crv": "P-384",
            "x": "WjB-nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0",
            "y": "Z-0_tDH_r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs_mcmvPqVK9j",
            "x5c": [
                "MIIBzDCCAVOgAwIBAgIJAJM4DhRH0vmuMAoGCCqGSM49BAMEMB4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMTgwNTEzMTkzMzQ3WhcNMjMwNTEyMTkzMzQ3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWjB+nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0Z+0/tDH/r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs/mcmvPqVK9jo10wWzAdBgNVHQ4EFgQUh6XzV6LwNazA+GTEVOdu07o5yOgwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwGQYDVR0RBBIwEIYOc3BpZmZlOi8vbG9jYWwwCgYIKoZIzj0EAwQDZwAwZAIwE4Me13qMC9i6Fkx0h26y09QZIbuRqA9puLg9AeeAAyo5tBzRl1YL0KNEp02VKSYJAjBdeJvqjJ9wW55OGj1JQwDFD7kWeEB6oMlwPbI/5hEY3azJi16I0uN1JSYTSWGSqWc="
            ]
        },
        { # upstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
            "crv": "P-256",
            "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
            "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
        },
        { # downstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "v7WFMeyjcmRi895PP0Kzis6iKVFcjrgt",
            "crv": "P-256",
            "x": "TTiFdYM2b2IZ0otfPD3oB14rULysd0PsQ-V3eZf56SM",
            "y": "cXFVTawAcfyv2sYD0vo3Nh0MLT7BdJ_bIXKR2z33YWM"
        },
        { # downstream-spire-1の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "5rtNSCHGanu4zZxHEMElcD40EpEXWWBy",
            "crv": "P-256",
            "x": "JcAOx-y9l0irle-4dIn6XN7ei5Kxtq9TGlDNTyRpRec",
            "y": "At-3XXCrVs5OBiTKcwCIhA9lj_iGf05lWaOS6LxBo_4"
        }
    ]
}


downstream-spire-1 $ sudo spire-server experimental bundle show
{
    "keys": [
        {
            "use": "x509-svid",
            "kty": "EC",
            "crv": "P-384",
            "x": "WjB-nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0",
            "y": "Z-0_tDH_r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs_mcmvPqVK9j",
            "x5c": [
                "MIIBzDCCAVOgAwIBAgIJAJM4DhRH0vmuMAoGCCqGSM49BAMEMB4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZTUElGRkUwHhcNMTgwNTEzMTkzMzQ3WhcNMjMwNTEyMTkzMzQ3WjAeMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGU1BJRkZFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWjB+nSGSxIYiznb84xu5WGDZj80nL7W1c3zf48Why0ma7Y7mCBKzfQkrgDguI4j0Z+0/tDH/r8gtOtLLrIpuMwWHoe4vbVBFte1vj6Xt6WeE8lXwcCvLs/mcmvPqVK9jo10wWzAdBgNVHQ4EFgQUh6XzV6LwNazA+GTEVOdu07o5yOgwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwGQYDVR0RBBIwEIYOc3BpZmZlOi8vbG9jYWwwCgYIKoZIzj0EAwQDZwAwZAIwE4Me13qMC9i6Fkx0h26y09QZIbuRqA9puLg9AeeAAyo5tBzRl1YL0KNEp02VKSYJAjBdeJvqjJ9wW55OGj1JQwDFD7kWeEB6oMlwPbI/5hEY3azJi16I0uN1JSYTSWGSqWc="
            ]
        },
        { # upstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
            "crv": "P-256",
            "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
            "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
        },
        { # downstream-spire-0の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "v7WFMeyjcmRi895PP0Kzis6iKVFcjrgt",
            "crv": "P-256",
            "x": "TTiFdYM2b2IZ0otfPD3oB14rULysd0PsQ-V3eZf56SM",
            "y": "cXFVTawAcfyv2sYD0vo3Nh0MLT7BdJ_bIXKR2z33YWM"
        },
        { # downstream-spire-1の検証鍵
            "use": "jwt-svid",
            "kty": "EC",
            "kid": "5rtNSCHGanu4zZxHEMElcD40EpEXWWBy",
            "crv": "P-256",
            "x": "JcAOx-y9l0irle-4dIn6XN7ei5Kxtq9TGlDNTyRpRec",
            "y": "At-3XXCrVs5OBiTKcwCIhA9lj_iGf05lWaOS6LxBo_4"
        }
    ]
}

Workload APIからJWT検証鍵一覧を取得してみる

ここまででSPIRE Serverには鍵が正しく伝搬されていることが確認できました。
最後に、WorkloadがSPIRE Agentを使ってDownstream SPIRE Serverから鍵の束を取得できることを確認してみたいと思います。

Node Attestation用Join Tokenの発行

downstream-spire-0 $ sudo spire-server token generate -spiffeID spiffe://example.org/nodes/my-node
Token: 679f5b05-ca6c-4a10-8362-13aaa61ef86c

テスト用WorkloadのEntry作成

downstream-spire-0 $ sudo spire-server entry create 
-parentID spiffe://example.org/nodes/my-node 
-spiffeID spiffe://example.org/workloads/my-test-app 
-selector unix:uid:1000

Entry ID      : 9b892440-9227-4840-9f45-9eb9bd55080d
SPIFFE ID     : spiffe://example.org/workloads/my-test-app
Parent ID     : spiffe://example.org/nodes/my-node
TTL           : 3600
Selector      : unix:uid:1000

Agentの設定

agent {
    data_dir = "/var/lib/spire/data"
    log_level = "DEBUG"
    server_address = "${DOWNSTREAM_SPIRE_ADDR}"
    server_port = "8081"
    socket_path ="/tmp/agent.sock"
    trust_bundle_path = "/etc/spire/dummy_upstream_ca.crt"
    trust_domain = "example.org"
    join_token = "{JOIN_TOKEN}"
}

plugins {
    NodeAttestor "join_token" {
        plugin_data {
        }
    }
    KeyManager "disk" {
        plugin_data {
            directory = "/var/lib/spire/data/key"
        }
    }
    WorkloadAttestor "unix" {
        plugin_data {
        }
    }
}

Agentの起動

my-node $ sudo spire-agent run -config agent.conf

以下のようなテストアプリケーションを作成し、Workload API経由で検証鍵の束を取得します。

package main

import (
        "context"
        "fmt"
        "log"
        "time"
  
        "github.com/spiffe/go-spiffe/v2/spiffeid"
        "github.com/spiffe/go-spiffe/v2/workloadapi"
)

const (
        socketPath = "unix:///tmp/agent.sock"
        trustDomain = "example.org"
)

func main() {
        ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
        defer cancel()

        clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath))

        jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions)
        if err != nil {
                log.Fatalf("Unable to create JWTSource: %v", err)
        }
        defer jwtSource.Close()

        td, err := spiffeid.TrustDomainFromString(trustDomain)
        if err != nil {
                log.Fatalf("Unable to parse TrustDomain: %v", err)
        }

        bundles, err := jwtSource.GetJWTBundleForTrustDomain(td)
        if err != nil {
                log.Fatalf("Unable to fetch SVID: %v", err)
        }

        b, err := bundles.Marshal()
        if err != nil {
                log.Fatalf("Unable to marshal bundles: %v", err)
        }

        fmt.Println(string(b))
}

テスト用のアプリケーションはRegistrationEntryにしたがってuid=1000のユーザで実行します。

$ ./get-bundle  | jq .
{
  "keys": [
    {
      "kty": "EC",
      "kid": "4J21ZX6a0KC4SvtapHZ3Lixwte2YKYNP",
      "crv": "P-256",
      "x": "flO4U6AEGTAVw9PGXY8kjXzy9AxVMACbYdOMZKqZkAc",
      "y": "SFS9LYhUNdm1ja1HCYE_eBJ9IB-2EPydikaI2eaom_A"
    },
    {
      "kty": "EC",
      "kid": "v7WFMeyjcmRi895PP0Kzis6iKVFcjrgt",
      "crv": "P-256",
      "x": "TTiFdYM2b2IZ0otfPD3oB14rULysd0PsQ-V3eZf56SM",
      "y": "cXFVTawAcfyv2sYD0vo3Nh0MLT7BdJ_bIXKR2z33YWM"
    },
    {
      "kty": "EC",
      "kid": "5rtNSCHGanu4zZxHEMElcD40EpEXWWBy",
      "crv": "P-256",
      "x": "JcAOx-y9l0irle-4dIn6XN7ei5Kxtq9TGlDNTyRpRec",
      "y": "At-3XXCrVs5OBiTKcwCIhA9lj_iGf05lWaOS6LxBo_4"
    }
  ]
}

無事JWK Set形式ですべてのSPIRE Server分のJWT検証用の鍵を取得することができました。

まとめ

冗長化のためにSPIRE Serverを複数台で構成する場合、かつJWT SVIDを扱う必要がある場合にはUpstreamAuthority spire pluginでNested SPIREを構成する必要があります。
Upstream SPIRE Serverが提供する、CA証明書発行のエンドポイントへの接続には、Upstream SPIRE ServerのRegistrationEntryでdownstreamフラグがたっているSPIFFE IDを含むSVIDが必要になります。
UpstreamAuthority spire pluginは、SPIRE Agent経由でUpstream SPIRE Serverへの接続に必要なSVIDを取得するため、Downstream SPIREのノードにはSPIRE ServerとSPIRE Agentを同居させる必要があります。

UpstreamAuthority pluguinの話はこのあたりで終わりにして、明日のエントリではワンタイムトークンを使ったNode Attestationではなく、証明書を使ったNode Attestationについて触れてみたいと思います。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?