Skip to content

Commit

Permalink
Expose local SPIFFE CA's JWT keypairs in SPIFFE trust bundles
Browse files Browse the repository at this point in the history
  • Loading branch information
strideynet authored and github-actions committed Sep 23, 2024
1 parent 15fcdf4 commit 88ec46b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
19 changes: 19 additions & 0 deletions lib/tbot/spiffe/trust_bundle_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import (
machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
trustv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/jwt"
"github.com/gravitational/teleport/lib/services"
)

Expand Down Expand Up @@ -610,6 +612,8 @@ func convertSPIFFECAToBundle(ca types.CertAuthority) (*spiffebundle.Bundle, erro
}

bundle := spiffebundle.New(td)

// Add X509 authorities to the trust bundle.
for _, certBytes := range services.GetTLSCerts(ca) {
block, _ := pem.Decode(certBytes)
cert, err := x509.ParseCertificate(block.Bytes)
Expand All @@ -619,6 +623,21 @@ func convertSPIFFECAToBundle(ca types.CertAuthority) (*spiffebundle.Bundle, erro
bundle.AddX509Authority(cert)
}

// Add JWT authorities to the trust bundle.
for _, keyPair := range ca.GetTrustedJWTKeyPairs() {
pubKey, err := keys.ParsePublicKey(keyPair.PublicKey)
if err != nil {
return nil, trace.Wrap(err, "parsing public key")
}
kid, err := jwt.KeyID(pubKey)
if err != nil {
return nil, trace.Wrap(err, "generating key ID")
}
if err := bundle.AddJWTAuthority(kid, pubKey); err != nil {
return nil, trace.Wrap(err, "adding JWT authority to bundle")
}
}

return bundle, nil
}

Expand Down
20 changes: 20 additions & 0 deletions lib/tbot/spiffe/trust_bundle_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package spiffe

import (
"context"
"crypto"
"crypto/x509/pkix"
"testing"
"time"
Expand All @@ -35,6 +36,9 @@ import (
machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
trustv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/auth/testauthority"
"github.com/gravitational/teleport/lib/jwt"
"github.com/gravitational/teleport/lib/tlsca"
"github.com/gravitational/teleport/lib/utils"
)
Expand Down Expand Up @@ -176,6 +180,12 @@ func TestTrustBundleCache_Run(t *testing.T) {
require.NoError(t, err)
caCert, err := tlsca.ParseCertificatePEM(caCertPEM)
require.NoError(t, err)
jwtCAPublic, jwtCAPrivate, err := testauthority.New().GenerateJWT()
require.NoError(t, err)
jwtCA, err := keys.ParsePublicKey(jwtCAPublic)
require.NoError(t, err)
jwtCAKID, err := jwt.KeyID(jwtCA)
require.NoError(t, err)
ca, err := types.NewCertAuthority(types.CertAuthoritySpecV2{
Type: types.SPIFFECA,
ClusterName: "example.com",
Expand All @@ -186,6 +196,12 @@ func TestTrustBundleCache_Run(t *testing.T) {
Key: caKey,
},
},
JWT: []*types.JWTKeyPair{
{
PublicKey: jwtCAPublic,
PrivateKey: jwtCAPrivate,
},
},
},
})
require.NoError(t, err)
Expand Down Expand Up @@ -233,6 +249,10 @@ func TestTrustBundleCache_Run(t *testing.T) {
require.Equal(t, "example.com", gotBundleSet.Local.TrustDomain().Name())
require.Len(t, gotBundleSet.Local.X509Authorities(), 1)
require.True(t, gotBundleSet.Local.X509Authorities()[0].Equal(caCert))
require.Len(t, gotBundleSet.Local.JWTAuthorities(), 1)
gotBundleJWTKey, ok := gotBundleSet.Local.FindJWTAuthority(jwtCAKID)
require.True(t, ok, "public key not found in bundle")
require.True(t, gotBundleJWTKey.(interface{ Equal(x crypto.PublicKey) bool }).Equal(jwtCA), "public keys do not match")
// Check the federated bundle
gotFederatedBundle, ok := gotBundleSet.Federated["pre-init-federated.example.com"]
require.True(t, ok)
Expand Down
18 changes: 18 additions & 0 deletions lib/web/spiffe.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"github.com/spiffe/go-spiffe/v2/spiffeid"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/jwt"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/tlsca"
)
Expand Down Expand Up @@ -71,6 +73,7 @@ func (h *Handler) getSPIFFEBundle(w http.ResponseWriter, r *http.Request, _ http
return nil, trace.Wrap(err, "fetching SPIFFE CA")
}

// Add X509 authorities to the trust bundle.
for _, certPEM := range services.GetTLSCerts(spiffeCA) {
cert, err := tlsca.ParseCertificatePEM(certPEM)
if err != nil {
Expand All @@ -79,6 +82,21 @@ func (h *Handler) getSPIFFEBundle(w http.ResponseWriter, r *http.Request, _ http
bundle.AddX509Authority(cert)
}

// Add JWT authorities to the trust bundle.
for _, keyPair := range spiffeCA.GetTrustedJWTKeyPairs() {
pubKey, err := keys.ParsePublicKey(keyPair.PublicKey)
if err != nil {
return nil, trace.Wrap(err, "parsing public key")
}
kid, err := jwt.KeyID(pubKey)
if err != nil {
return nil, trace.Wrap(err, "generating key ID")
}
if err := bundle.AddJWTAuthority(kid, pubKey); err != nil {
return nil, trace.Wrap(err, "adding JWT authority to bundle")
}
}

bundleBytes, err := bundle.Marshal()
if err != nil {
return nil, trace.Wrap(err, "marshaling bundle")
Expand Down
14 changes: 14 additions & 0 deletions lib/web/spiffe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package web

import (
"context"
"crypto"
"crypto/x509"
"testing"

Expand All @@ -29,7 +30,9 @@ import (
"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/jwt"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/tlsca"
)
Expand Down Expand Up @@ -68,4 +71,15 @@ func TestGetSPIFFEBundle(t *testing.T) {
for _, caCert := range wantCACerts {
require.True(t, gotBundle.HasX509Authority(caCert), "certificate not found in bundle")
}

require.Len(t, gotBundle.JWTAuthorities(), len(ca.GetTrustedJWTKeyPairs()))
for _, jwtKeyPair := range ca.GetTrustedJWTKeyPairs() {
wantKey, err := keys.ParsePublicKey(jwtKeyPair.PublicKey)
require.NoError(t, err)
wantKeyID, err := jwt.KeyID(wantKey)
require.NoError(t, err)
gotPubKey, ok := gotBundle.JWTBundle().FindJWTAuthority(wantKeyID)
require.True(t, ok, "wanted public key not found in bundle")
require.True(t, gotPubKey.(interface{ Equal(x crypto.PublicKey) bool }).Equal(wantKey), "public keys do not match")
}
}

0 comments on commit 88ec46b

Please sign in to comment.