diff --git a/command/ca/provisioner/provisioner.go b/command/ca/provisioner/provisioner.go index 54e92217e..c0e9bcff8 100644 --- a/command/ca/provisioner/provisioner.go +++ b/command/ca/provisioner/provisioner.go @@ -651,14 +651,14 @@ func readNebulaRoots(rootFile string) ([][]byte, error) { return nil, err } - var crt *nebula.NebulaCertificate - var certs []*nebula.NebulaCertificate + var crt nebula.Certificate + var certs []nebula.Certificate for len(b) > 0 { - crt, b, err = nebula.UnmarshalNebulaCertificateFromPEM(b) + crt, b, err = nebula.UnmarshalCertificateFromPEM(b) if err != nil { return nil, errors.Wrapf(err, "error reading %s", rootFile) } - if crt.Details.IsCA { + if crt.IsCA() { certs = append(certs, crt) } } @@ -668,7 +668,7 @@ func readNebulaRoots(rootFile string) ([][]byte, error) { rootBytes := make([][]byte, len(certs)) for i, crt := range certs { - b, err = crt.MarshalToPEM() + b, err = crt.MarshalPEM() if err != nil { return nil, errors.Wrap(err, "error marshaling certificate") } diff --git a/command/ca/provisioner/provisioner_test.go b/command/ca/provisioner/provisioner_test.go new file mode 100644 index 000000000..fe0168bfb --- /dev/null +++ b/command/ca/provisioner/provisioner_test.go @@ -0,0 +1,97 @@ +package provisioner + +import ( + "crypto/ed25519" + "crypto/rand" + "net/netip" + "os" + "testing" + "time" + + nebula "github.com/slackhq/nebula/cert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestReadNebulaRoots(t *testing.T) { + t.Run("ok", func(t *testing.T) { + tempDir := t.TempDir() + ca, _ := mustNebulaCurve25519CA(t) + file, _ := serializeAndWriteNebulaCert(t, tempDir, ca) + + roots, err := readNebulaRoots(file) + assert.NoError(t, err) + assert.Len(t, roots, 1) + }) + + t.Run("fail/reading", func(t *testing.T) { + roots, err := readNebulaRoots("non-existing-file") + assert.Error(t, err) + assert.Empty(t, roots) + }) + + t.Run("fail/invalid-pem", func(t *testing.T) { + tempDir := t.TempDir() + + file, err := os.CreateTemp(tempDir, "nebula-test-cert-*") + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte{0}) + require.NoError(t, err) + + roots, err := readNebulaRoots(file.Name()) + assert.Error(t, err) + assert.Empty(t, roots) + }) + + t.Run("fail/no-certificates", func(t *testing.T) { + tempDir := t.TempDir() + + file, err := os.CreateTemp(tempDir, "nebula-test-cert-*") + require.NoError(t, err) + defer file.Close() + + roots, err := readNebulaRoots(file.Name()) + assert.Error(t, err) + assert.Empty(t, roots) + }) +} + +func mustNebulaCurve25519CA(t *testing.T) (nebula.Certificate, ed25519.PrivateKey) { + t.Helper() + + pub, priv, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + tbs := &nebula.TBSCertificate{ + Version: nebula.Version1, + Name: "TestCA", + Groups: []string{"test"}, + Networks: []netip.Prefix{netip.MustParsePrefix("10.1.0.0/16")}, + NotBefore: time.Now().Add(-1 * time.Minute), + NotAfter: time.Now().Add(10 * time.Minute), + PublicKey: pub, + IsCA: true, + Curve: nebula.Curve_CURVE25519, + } + nc, err := tbs.Sign(nil, nebula.Curve_CURVE25519, priv) + require.NoError(t, err) + + return nc, priv +} + +func serializeAndWriteNebulaCert(t *testing.T, tempDir string, cert nebula.Certificate) (string, []byte) { + file, err := os.CreateTemp(tempDir, "nebula-test-cert-*") + require.NoError(t, err) + defer file.Close() + + pem, err := cert.MarshalPEM() + require.NoError(t, err) + data, err := cert.Marshal() + require.NoError(t, err) + _, err = file.Write(pem) + require.NoError(t, err) + + return file.Name(), data +} diff --git a/go.mod b/go.mod index 76ad59d80..fb7b0ab18 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/smallstep/cli -go 1.24.0 +go 1.25 require ( github.com/Microsoft/go-winio v0.6.2 @@ -14,9 +14,9 @@ require ( github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.5.0 github.com/rogpeppe/go-internal v1.14.1 - github.com/slackhq/nebula v1.9.7 + github.com/slackhq/nebula v1.10.3 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 - github.com/smallstep/certificates v0.29.0 + github.com/smallstep/certificates v0.30.0-rc2.0.20260217112636-bb94179fa4c6 github.com/smallstep/certinfo v1.15.0 github.com/smallstep/cli-utils v0.12.2 github.com/smallstep/go-attestation v0.4.4-0.20241119153605-2306d5b464ca @@ -43,7 +43,8 @@ require ( cloud.google.com/go/iam v1.5.3 // indirect cloud.google.com/go/longrunning v0.8.0 // indirect cloud.google.com/go/security v1.19.2 // indirect - dario.cat/mergo v1.0.1 // indirect + dario.cat/mergo v1.0.2 // indirect + filippo.io/bigmod v0.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect @@ -62,7 +63,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect - github.com/coreos/go-systemd/v22 v22.6.0 // indirect + github.com/coreos/go-systemd/v22 v22.7.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgraph-io/badger v1.6.2 // indirect @@ -71,7 +72,7 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-chi/chi/v5 v5.2.3 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -106,14 +107,14 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/rs/xid v1.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/jsonstore v1.1.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/smallstep/nosql v0.7.0 // indirect github.com/smallstep/pkcs7 v0.2.1 // indirect github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492 // indirect @@ -127,18 +128,18 @@ require ( go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.39.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.49.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/net v0.50.0 // indirect + golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.41.0 // indirect - google.golang.org/api v0.264.0 // indirect + golang.org/x/tools v0.42.0 // indirect + google.golang.org/api v0.266.0 // indirect google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect - google.golang.org/grpc v1.78.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect + google.golang.org/grpc v1.79.1 // indirect google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.0 // indirect diff --git a/go.sum b/go.sum index f5a1c44c5..0b617e798 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,10 @@ cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7 cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk= cloud.google.com/go/security v1.19.2 h1:cF3FkCRRbRC1oXuaGZFl3qU2sdu2gP3iOAHKzL5y04Y= cloud.google.com/go/security v1.19.2/go.mod h1:KXmf64mnOsLVKe8mk/bZpU1Rsvxqc0Ej0A6tgCeN93w= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +filippo.io/bigmod v0.1.0 h1:UNzDk7y9ADKST+axd9skUpBQeW7fG2KrTZyOE4uGQy8= +filippo.io/bigmod v0.1.0/go.mod h1:OjOXDNlClLblvXdwgFFOQFJEocLhhtai8vGLy0JCZlI= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= @@ -102,15 +104,15 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= -github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= -github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= +github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= +github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -132,11 +134,11 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= -github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= -github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -144,8 +146,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= @@ -268,10 +270,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= @@ -285,14 +287,14 @@ github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/slackhq/nebula v1.9.7 h1:v5u46efIyYHGdfjFnozQbRRhMdaB9Ma1SSTcUcE2lfE= -github.com/slackhq/nebula v1.9.7/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/slackhq/nebula v1.10.3 h1:EstYj8ODEcv6T0R9X5BVq1zgWZnyU5gtPzk99QF1PMU= +github.com/slackhq/nebula v1.10.3/go.mod h1:IL5TUQm4x9IFx2kCKPYm1gP47pwd5b8QGnnBH2RHnvs= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smallstep/certificates v0.29.0 h1:f90szTKYTW62bmCc+qE5doGqIGPVxTQb8Ba37e/K8Zs= -github.com/smallstep/certificates v0.29.0/go.mod h1:27WI0od6gu84mvE4mYQ/QZGyYwHXvhsiSRNC+y3t+mo= +github.com/smallstep/certificates v0.30.0-rc2.0.20260217112636-bb94179fa4c6 h1:j184ovnJvsBkG18giCQOjeQBlcSzvbjGZm90c7OugiU= +github.com/smallstep/certificates v0.30.0-rc2.0.20260217112636-bb94179fa4c6/go.mod h1:h9TiplQL15M/zN1pm4tt31KRuEs6blf7IvFCO2GJkgQ= github.com/smallstep/certinfo v1.15.0 h1:oxvuOr6KvwuXjgyg+gJEUJW6Gz9pm4uAGQ5tirpmTHg= github.com/smallstep/certinfo v1.15.0/go.mod h1:t5s4J23P3B/j68l2efuJFSZqCj0kBU8sa2FYbHRaffw= github.com/smallstep/cli-utils v0.12.2 h1:lGzM9PJrH/qawbzMC/s2SvgLdJPKDWKwKzx9doCVO+k= @@ -365,8 +367,8 @@ go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.step.sm/crypto v0.76.2 h1:JJ/yMcs/rmcCAwlo+afrHjq74XBFRTJw5B2y4Q4Z4c4= @@ -377,8 +379,8 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -402,10 +404,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -423,7 +425,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -466,21 +467,21 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/api v0.264.0 h1:+Fo3DQXBK8gLdf8rFZ3uLu39JpOnhvzJrLMQSoSYZJM= -google.golang.org/api v0.264.0/go.mod h1:fAU1xtNNisHgOF5JooAs8rRaTkl2rT3uaoNGo9NS3R8= +google.golang.org/api v0.266.0 h1:hco+oNCf9y7DmLeAtHJi/uBAY7n/7XC9mZPxu1ROiyk= +google.golang.org/api v0.266.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= +google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= diff --git a/token/options.go b/token/options.go index 3ceb1d1b2..f956466af 100644 --- a/token/options.go +++ b/token/options.go @@ -264,14 +264,19 @@ func WithNebulaCert(certFile string, anyKey any) Options { if err != nil { return errors.Wrapf(err, "error reading %s", certFile) } + + blockType := nebula.CertificateBanner // default to a v1 Nebula certificate if bytes.HasPrefix(b, pemCertPrefix) { block, _ := pem.Decode(b) - if block == nil || block.Type != nebula.CertBanner { + if block == nil || (block.Type != nebula.CertificateBanner && block.Type != nebula.CertificateV2Banner) { return errors.Errorf("error reading %s: not a proper nebula certificate", certFile) } b = block.Bytes + blockType = block.Type } - crt, err := nebula.UnmarshalNebulaCertificate(b) + + pemData := pem.EncodeToMemory(&pem.Block{Type: blockType, Bytes: b}) + crt, _, err := nebula.UnmarshalCertificateFromPEM(pemData) if err != nil { return errors.Wrapf(err, "error reading %s", certFile) } diff --git a/token/options_test.go b/token/options_test.go index 5b7e209db..f3bd134ae 100644 --- a/token/options_test.go +++ b/token/options_test.go @@ -7,6 +7,7 @@ import ( "crypto/elliptic" "crypto/rand" "net" + "net/netip" "os" "path/filepath" "testing" @@ -15,15 +16,17 @@ import ( nebula "github.com/slackhq/nebula/cert" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/crypto/ssh" + "go.step.sm/crypto/jose" "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x25519" - "golang.org/x/crypto/ssh" ) func TestOptions(t *testing.T) { empty := new(Claims) now := time.Now() + c25519CACert, c25519CAKey := mustNebulaCurve25519CA(t) p256CACert, p256CAKey := mustNebulaP256CA(t) c25519Cert, c25519Signer := mustNebulaCurve25519Cert(t, "test.lan", mustNebulaIPNet(t, "10.1.0.1/16"), []string{"test"}, c25519CACert, c25519CAKey) @@ -119,16 +122,18 @@ func mustReadSSHPublicKey(t *testing.T, filename string) ssh.PublicKey { return pub } -func serializeAndWriteNebulaCert(t *testing.T, tempDir string, cert *nebula.NebulaCertificate) (string, []byte) { +func serializeAndWriteNebulaCert(t *testing.T, tempDir string, cert nebula.Certificate) (string, []byte) { file, err := os.CreateTemp(tempDir, "nebula-test-cert-*") require.NoError(t, err) defer file.Close() - pem, err := cert.MarshalToPEM() + + pem, err := cert.MarshalPEM() require.NoError(t, err) data, err := cert.Marshal() require.NoError(t, err) _, err = file.Write(pem) require.NoError(t, err) + return file.Name(), data } @@ -145,65 +150,57 @@ func mustNebulaIPNet(t *testing.T, s string) *net.IPNet { return ipNet } -func mustNebulaCurve25519CA(t *testing.T) (*nebula.NebulaCertificate, ed25519.PrivateKey) { +func mustNebulaCurve25519CA(t *testing.T) (nebula.Certificate, ed25519.PrivateKey) { t.Helper() + pub, priv, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - nc := &nebula.NebulaCertificate{ - Details: nebula.NebulaCertificateDetails{ - Name: "TestCA", - Groups: []string{"test"}, - Ips: []*net.IPNet{ - mustNebulaIPNet(t, "10.1.0.0/16"), - }, - Subnets: []*net.IPNet{}, - NotBefore: time.Now(), - NotAfter: time.Now().Add(10 * time.Minute), - PublicKey: pub, - IsCA: true, - Curve: nebula.Curve_CURVE25519, - }, + tbs := &nebula.TBSCertificate{ + Version: nebula.Version1, + Name: "TestCA", + Groups: []string{"test"}, + Networks: []netip.Prefix{netip.MustParsePrefix("10.1.0.0/16")}, + NotBefore: time.Now().Add(-1 * time.Minute), + NotAfter: time.Now().Add(10 * time.Minute), + PublicKey: pub, + IsCA: true, + Curve: nebula.Curve_CURVE25519, } - - require.NoError(t, nc.Sign(nebula.Curve_CURVE25519, priv)) + nc, err := tbs.Sign(nil, nebula.Curve_CURVE25519, priv) + require.NoError(t, err) return nc, priv } -func mustNebulaP256CA(t *testing.T) (*nebula.NebulaCertificate, *ecdh.PrivateKey) { +func mustNebulaP256CA(t *testing.T) (nebula.Certificate, *ecdh.PrivateKey) { t.Helper() + priv, err := ecdh.P256().GenerateKey(rand.Reader) require.NoError(t, err) - nc := &nebula.NebulaCertificate{ - Details: nebula.NebulaCertificateDetails{ - Name: "TestCA", - Groups: []string{"test"}, - Ips: []*net.IPNet{ - mustNebulaIPNet(t, "10.1.0.0/16"), - }, - Subnets: []*net.IPNet{}, - NotBefore: time.Now(), - NotAfter: time.Now().Add(10 * time.Minute), - PublicKey: priv.PublicKey().Bytes(), - IsCA: true, - Curve: nebula.Curve_P256, - }, + tbs := &nebula.TBSCertificate{ + Version: nebula.Version1, + Name: "TestCA", + Groups: []string{"test"}, + Networks: []netip.Prefix{netip.MustParsePrefix("10.1.0.0/16")}, + NotBefore: time.Now().Add(-1 * time.Minute), + NotAfter: time.Now().Add(10 * time.Minute), + PublicKey: priv.PublicKey().Bytes(), + IsCA: true, + Curve: nebula.Curve_P256, } - - require.NoError(t, nc.Sign(nebula.Curve_P256, priv.Bytes())) + nc, err := tbs.Sign(nil, nebula.Curve_P256, priv.Bytes()) + require.NoError(t, err) return nc, priv } -func mustNebulaCurve25519Cert(t *testing.T, name string, ipNet *net.IPNet, groups []string, ca *nebula.NebulaCertificate, signer ed25519.PrivateKey) (*nebula.NebulaCertificate, x25519.PrivateKey) { +func mustNebulaCurve25519Cert(t *testing.T, name string, ipNet *net.IPNet, groups []string, ca nebula.Certificate, signer ed25519.PrivateKey) (nebula.Certificate, x25519.PrivateKey) { t.Helper() pub, priv, err := x25519.GenerateKey(rand.Reader) require.NoError(t, err) - issuer, err := ca.Sha256Sum() - require.NoError(t, err) invertedGroups := make(map[string]struct{}, len(groups)) for _, name := range groups { @@ -214,34 +211,29 @@ func mustNebulaCurve25519Cert(t *testing.T, name string, ipNet *net.IPNet, group curve := nebula.Curve_CURVE25519 t1 := time.Now().Truncate(time.Second) - nc := &nebula.NebulaCertificate{ - Details: nebula.NebulaCertificateDetails{ - Name: name, - Ips: []*net.IPNet{ipNet}, - Subnets: []*net.IPNet{}, - Groups: groups, - NotBefore: t1, - NotAfter: t1.Add(5 * time.Minute), - PublicKey: pub, - IsCA: false, - Issuer: issuer, - InvertedGroups: invertedGroups, - Curve: curve, - }, + tbs := &nebula.TBSCertificate{ + Version: nebula.Version1, + Name: name, + Networks: []netip.Prefix{netip.MustParsePrefix(ipNet.String())}, + Groups: groups, + NotBefore: t1, + NotAfter: t1.Add(5 * time.Minute), + PublicKey: pub, + IsCA: false, + Curve: curve, } - require.NoError(t, nc.Sign(curve, key)) + nc, err := tbs.Sign(ca, curve, key) + require.NoError(t, err) return nc, priv } -func mustNebulaP256Cert(t *testing.T, name string, ipNet *net.IPNet, groups []string, ca *nebula.NebulaCertificate, signer *ecdh.PrivateKey) (*nebula.NebulaCertificate, *ecdsa.PrivateKey) { +func mustNebulaP256Cert(t *testing.T, name string, ipNet *net.IPNet, groups []string, ca nebula.Certificate, signer *ecdh.PrivateKey) (nebula.Certificate, *ecdsa.PrivateKey) { t.Helper() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) - issuer, err := ca.Sha256Sum() - require.NoError(t, err) invertedGroups := make(map[string]struct{}, len(groups)) for _, name := range groups { @@ -255,23 +247,20 @@ func mustNebulaP256Cert(t *testing.T, name string, ipNet *net.IPNet, groups []st require.NoError(t, err) t1 := time.Now().Truncate(time.Second) - nc := &nebula.NebulaCertificate{ - Details: nebula.NebulaCertificateDetails{ - Name: name, - Ips: []*net.IPNet{ipNet}, - Subnets: []*net.IPNet{}, - Groups: groups, - NotBefore: t1, - NotAfter: t1.Add(5 * time.Minute), - PublicKey: pk.PublicKey().Bytes(), - IsCA: false, - Issuer: issuer, - InvertedGroups: invertedGroups, - Curve: curve, - }, + tbs := &nebula.TBSCertificate{ + Version: nebula.Version2, + Name: name, + Networks: []netip.Prefix{netip.MustParsePrefix(ipNet.String())}, + Groups: groups, + NotBefore: t1, + NotAfter: t1.Add(5 * time.Minute), + PublicKey: pk.PublicKey().Bytes(), + IsCA: false, + Curve: curve, } - require.NoError(t, nc.Sign(curve, key)) + nc, err := tbs.Sign(ca, curve, key) + require.NoError(t, err) return nc, priv }