Compare commits

..

1 commit

Author SHA1 Message Date
Mariano Cano
7fa97bedec
Remove OIDC user regexp check
This commit removes the regular expression check on OIDC usernames.
Although it is not recommended to use any character in a username,
it is possible to create and use them. The tool useradd has the flag
--badname and adduser has --allow-badname and --allow-all-names to
create new users with any character.

Moreover, it is possible to create any username with the rest of
provisioners.

Fixes #1436
2023-07-19 11:05:01 -07:00
17 changed files with 74 additions and 368 deletions

View file

@ -24,7 +24,6 @@ import (
"go.step.sm/linkedca"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/webhook"
)
// awsIssuer is the string used as issuer in the generated tokens.
@ -522,11 +521,7 @@ func (p *AWS) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro
commonNameValidator(payload.Claims.Subject),
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.ctl.getPolicy().getX509()),
p.ctl.newWebhookController(
data,
linkedca.Webhook_X509,
webhook.WithAuthorizationPrincipal(doc.InstanceID),
),
p.ctl.newWebhookController(data, linkedca.Webhook_X509),
), nil
}
@ -809,10 +804,6 @@ func (p *AWS) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
// Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil),
// Call webhooks
p.ctl.newWebhookController(
data,
linkedca.Webhook_SSH,
webhook.WithAuthorizationPrincipal(doc.InstanceID),
),
p.ctl.newWebhookController(data, linkedca.Webhook_SSH),
), nil
}

View file

@ -20,7 +20,6 @@ import (
"go.step.sm/linkedca"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/webhook"
)
// azureOIDCBaseURL is the base discovery url for Microsoft Azure tokens.
@ -404,11 +403,7 @@ func (p *Azure) AuthorizeSign(_ context.Context, token string) ([]SignOption, er
defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.ctl.getPolicy().getX509()),
p.ctl.newWebhookController(
data,
linkedca.Webhook_X509,
webhook.WithAuthorizationPrincipal(identityObjectID),
),
p.ctl.newWebhookController(data, linkedca.Webhook_X509),
), nil
}
@ -426,7 +421,7 @@ func (p *Azure) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption,
return nil, errs.Unauthorized("azure.AuthorizeSSHSign; sshCA is disabled for provisioner '%s'", p.GetName())
}
_, name, _, _, identityObjectID, err := p.authorizeToken(token)
_, name, _, _, _, err := p.authorizeToken(token)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign")
}
@ -478,11 +473,7 @@ func (p *Azure) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption,
// Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil),
// Call webhooks
p.ctl.newWebhookController(
data,
linkedca.Webhook_SSH,
webhook.WithAuthorizationPrincipal(identityObjectID),
),
p.ctl.newWebhookController(data, linkedca.Webhook_SSH),
), nil
}

View file

@ -4,13 +4,11 @@ import (
"context"
"crypto/x509"
"net/http"
"regexp"
"strings"
"time"
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/webhook"
"go.step.sm/linkedca"
"golang.org/x/crypto/ssh"
)
@ -78,7 +76,7 @@ func (c *Controller) AuthorizeSSHRenew(ctx context.Context, cert *ssh.Certificat
return DefaultAuthorizeSSHRenew(ctx, c, cert)
}
func (c *Controller) newWebhookController(templateData WebhookSetter, certType linkedca.Webhook_CertType, opts ...webhook.RequestBodyOption) *WebhookController {
func (c *Controller) newWebhookController(templateData WebhookSetter, certType linkedca.Webhook_CertType) *WebhookController {
client := c.webhookClient
if client == nil {
client = http.DefaultClient
@ -88,7 +86,6 @@ func (c *Controller) newWebhookController(templateData WebhookSetter, certType l
client: client,
webhooks: c.webhooks,
certType: certType,
options: opts,
}
}
@ -117,20 +114,18 @@ func DefaultIdentityFunc(_ context.Context, p Interface, email string) (*Identit
switch k := p.(type) {
case *OIDC:
// OIDC principals would be:
// ~~1. Preferred usernames.~~ Note: Under discussion, currently disabled
// 2. Sanitized local.
// 3. Raw local (if different).
// 4. Email address.
// ~~1. Preferred usernames.~~ Note: Under discussion, currently disabled
// 2. Sanitized local.
// 3. Raw local (if different).
// 4. Email address.
name := SanitizeSSHUserPrincipal(email)
if !sshUserRegex.MatchString(name) {
return nil, errors.Errorf("invalid principal '%s' from email '%s'", name, email)
}
usernames := []string{name}
if i := strings.LastIndex(email, "@"); i >= 0 {
usernames = append(usernames, email[:i])
}
usernames = append(usernames, email)
return &Identity{
// Remove duplicated and empty usernames.
Usernames: SanitizeStringSlices(usernames),
}, nil
default:
@ -180,8 +175,6 @@ func DefaultAuthorizeSSHRenew(_ context.Context, p *Controller, cert *ssh.Certif
return nil
}
var sshUserRegex = regexp.MustCompile("^[a-z][-a-z0-9_]*$")
// SanitizeStringSlices removes duplicated an empty strings.
func SanitizeStringSlices(original []string) []string {
output := []string{}

View file

@ -4,18 +4,15 @@ import (
"context"
"crypto/x509"
"fmt"
"net/http"
"reflect"
"testing"
"time"
"go.step.sm/crypto/pemutil"
"go.step.sm/crypto/x509util"
"go.step.sm/linkedca"
"golang.org/x/crypto/ssh"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/webhook"
)
var trueValue = true
@ -170,6 +167,12 @@ func TestController_GetIdentity(t *testing.T) {
}}, args{ctx, "jane@doe.org"}, &Identity{
Usernames: []string{"jane"},
}, false},
{"ok badname", fields{&OIDC{}, nil}, args{ctx, "1000@doe.org"}, &Identity{
Usernames: []string{"1000", "1000@doe.org"},
}, false},
{"ok sanitized badname", fields{&OIDC{}, nil}, args{ctx, "1000+10@doe.org"}, &Identity{
Usernames: []string{"1000_10", "1000+10", "1000+10@doe.org"},
}, false},
{"fail provisioner", fields{&JWK{}, nil}, args{ctx, "jane@doe.org"}, nil, true},
{"fail custom", fields{&OIDC{}, func(ctx context.Context, p Interface, email string) (*Identity, error) {
return nil, fmt.Errorf("an error")
@ -452,39 +455,16 @@ func TestDefaultAuthorizeSSHRenew(t *testing.T) {
}
func Test_newWebhookController(t *testing.T) {
cert, err := pemutil.ReadCertificate("testdata/certs/x5c-leaf.crt", pemutil.WithFirstBlock())
if err != nil {
t.Fatal(err)
c := &Controller{}
data := x509util.TemplateData{"foo": "bar"}
ctl := c.newWebhookController(data, linkedca.Webhook_X509)
if !reflect.DeepEqual(ctl.TemplateData, data) {
t.Error("Failed to set templateData")
}
opts := []webhook.RequestBodyOption{webhook.WithX5CCertificate(cert)}
type args struct {
templateData WebhookSetter
certType linkedca.Webhook_CertType
opts []webhook.RequestBodyOption
if ctl.certType != linkedca.Webhook_X509 {
t.Error("Failed to set certType")
}
tests := []struct {
name string
args args
want *WebhookController
}{
{"ok", args{x509util.TemplateData{"foo": "bar"}, linkedca.Webhook_X509, nil}, &WebhookController{
TemplateData: x509util.TemplateData{"foo": "bar"},
certType: linkedca.Webhook_X509,
client: http.DefaultClient,
}},
{"ok with options", args{x509util.TemplateData{"foo": "bar"}, linkedca.Webhook_SSH, opts}, &WebhookController{
TemplateData: x509util.TemplateData{"foo": "bar"},
certType: linkedca.Webhook_SSH,
client: http.DefaultClient,
options: opts,
}},
}
for _, tt := range tests {
c := &Controller{}
got := c.newWebhookController(tt.args.templateData, tt.args.certType, tt.args.opts...)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("newWebhookController() = %v, want %v", got, tt.want)
}
if ctl.client == nil {
t.Error("Failed to set client")
}
}

View file

@ -21,7 +21,6 @@ import (
"go.step.sm/linkedca"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/webhook"
)
// gcpCertsURL is the url that serves Google OAuth2 public keys.
@ -276,11 +275,7 @@ func (p *GCP) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro
defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.ctl.getPolicy().getX509()),
p.ctl.newWebhookController(
data,
linkedca.Webhook_X509,
webhook.WithAuthorizationPrincipal(ce.InstanceID),
),
p.ctl.newWebhookController(data, linkedca.Webhook_X509),
), nil
}
@ -447,10 +442,6 @@ func (p *GCP) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
// Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil),
// Call webhooks
p.ctl.newWebhookController(
data,
linkedca.Webhook_SSH,
webhook.WithAuthorizationPrincipal(ce.InstanceID),
),
p.ctl.newWebhookController(data, linkedca.Webhook_SSH),
), nil
}

View file

@ -76,13 +76,6 @@ func TestDefaultIdentityFunc(t *testing.T) {
err: errors.New("provisioner type '*provisioner.X5C' not supported by identity function"),
}
},
"fail/bad-ssh-regex": func(t *testing.T) test {
return test{
p: &OIDC{},
email: "$%^#_>@smallstep.com",
err: errors.New("invalid principal '______' from email '$%^#_>@smallstep.com'"),
}
},
"ok": func(t *testing.T) test {
return test{
p: &OIDC{},
@ -142,6 +135,13 @@ func TestDefaultIdentityFunc(t *testing.T) {
identity: &Identity{Usernames: []string{"john", "john@smallstep.com"}},
}
},
"ok/badname": func(t *testing.T) test {
return test{
p: &OIDC{},
email: "$%^#_>@smallstep.com",
identity: &Identity{Usernames: []string{"______", "$%^#_>", "$%^#_>@smallstep.com"}},
}
},
}
for name, get := range tests {
t.Run(name, func(t *testing.T) {

View file

@ -30,7 +30,6 @@ type WebhookController struct {
client *http.Client
webhooks []*Webhook
certType linkedca.Webhook_CertType
options []webhook.RequestBodyOption
TemplateData WebhookSetter
}
@ -40,14 +39,6 @@ func (wc *WebhookController) Enrich(req *webhook.RequestBody) error {
if wc == nil {
return nil
}
// Apply extra options in the webhook controller
for _, fn := range wc.options {
if err := fn(req); err != nil {
return err
}
}
for _, wh := range wc.webhooks {
if wh.Kind != linkedca.Webhook_ENRICHING.String() {
continue
@ -72,14 +63,6 @@ func (wc *WebhookController) Authorize(req *webhook.RequestBody) error {
if wc == nil {
return nil
}
// Apply extra options in the webhook controller
for _, fn := range wc.options {
if err := fn(req); err != nil {
return err
}
}
for _, wh := range wc.webhooks {
if wh.Kind != linkedca.Webhook_AUTHORIZING.String() {
continue

View file

@ -4,7 +4,6 @@ import (
"crypto/hmac"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
@ -17,7 +16,6 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/assert"
"github.com/smallstep/certificates/webhook"
"go.step.sm/crypto/pemutil"
"go.step.sm/crypto/x509util"
"go.step.sm/linkedca"
)
@ -98,18 +96,12 @@ func TestWebhookController_isCertTypeOK(t *testing.T) {
}
func TestWebhookController_Enrich(t *testing.T) {
cert, err := pemutil.ReadCertificate("testdata/certs/x5c-leaf.crt", pemutil.WithFirstBlock())
if err != nil {
t.Fatal(err)
}
type test struct {
ctl *WebhookController
req *webhook.RequestBody
responses []*webhook.ResponseBody
expectErr bool
expectTemplateData any
assertRequest func(t *testing.T, req *webhook.RequestBody)
}
tests := map[string]test{
"ok/no enriching webhooks": {
@ -178,29 +170,6 @@ func TestWebhookController_Enrich(t *testing.T) {
},
},
},
"ok/with options": {
ctl: &WebhookController{
client: http.DefaultClient,
webhooks: []*Webhook{{Name: "people", Kind: "ENRICHING"}},
TemplateData: x509util.TemplateData{},
options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(cert)},
},
req: &webhook.RequestBody{},
responses: []*webhook.ResponseBody{{Allow: true, Data: map[string]any{"role": "bar"}}},
expectErr: false,
expectTemplateData: x509util.TemplateData{"Webhooks": map[string]any{"people": map[string]any{"role": "bar"}}},
assertRequest: func(t *testing.T, req *webhook.RequestBody) {
key, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
assert.FatalError(t, err)
assert.Equals(t, &webhook.X5CCertificate{
Raw: cert.Raw,
PublicKey: key,
PublicKeyAlgorithm: cert.PublicKeyAlgorithm.String(),
NotBefore: cert.NotBefore,
NotAfter: cert.NotAfter,
}, req.X5CCertificate)
},
},
"deny": {
ctl: &WebhookController{
client: http.DefaultClient,
@ -212,20 +181,6 @@ func TestWebhookController_Enrich(t *testing.T) {
expectErr: true,
expectTemplateData: x509util.TemplateData{},
},
"fail/with options": {
ctl: &WebhookController{
client: http.DefaultClient,
webhooks: []*Webhook{{Name: "people", Kind: "ENRICHING"}},
TemplateData: x509util.TemplateData{},
options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(&x509.Certificate{
PublicKey: []byte("bad"),
})},
},
req: &webhook.RequestBody{},
responses: []*webhook.ResponseBody{{Allow: false}},
expectErr: true,
expectTemplateData: x509util.TemplateData{},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
@ -245,25 +200,16 @@ func TestWebhookController_Enrich(t *testing.T) {
t.Fatalf("Got err %v, want %v", err, test.expectErr)
}
assert.Equals(t, test.expectTemplateData, test.ctl.TemplateData)
if test.assertRequest != nil {
test.assertRequest(t, test.req)
}
})
}
}
func TestWebhookController_Authorize(t *testing.T) {
cert, err := pemutil.ReadCertificate("testdata/certs/x5c-leaf.crt", pemutil.WithFirstBlock())
if err != nil {
t.Fatal(err)
}
type test struct {
ctl *WebhookController
req *webhook.RequestBody
responses []*webhook.ResponseBody
expectErr bool
assertRequest func(t *testing.T, req *webhook.RequestBody)
ctl *WebhookController
req *webhook.RequestBody
responses []*webhook.ResponseBody
expectErr bool
}
tests := map[string]test{
"ok/no enriching webhooks": {
@ -294,27 +240,6 @@ func TestWebhookController_Authorize(t *testing.T) {
responses: []*webhook.ResponseBody{{Allow: false}},
expectErr: false,
},
"ok/with options": {
ctl: &WebhookController{
client: http.DefaultClient,
webhooks: []*Webhook{{Name: "people", Kind: "AUTHORIZING"}},
options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(cert)},
},
req: &webhook.RequestBody{},
responses: []*webhook.ResponseBody{{Allow: true}},
expectErr: false,
assertRequest: func(t *testing.T, req *webhook.RequestBody) {
key, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
assert.FatalError(t, err)
assert.Equals(t, &webhook.X5CCertificate{
Raw: cert.Raw,
PublicKey: key,
PublicKeyAlgorithm: cert.PublicKeyAlgorithm.String(),
NotBefore: cert.NotBefore,
NotAfter: cert.NotAfter,
}, req.X5CCertificate)
},
},
"deny": {
ctl: &WebhookController{
client: http.DefaultClient,
@ -324,18 +249,6 @@ func TestWebhookController_Authorize(t *testing.T) {
responses: []*webhook.ResponseBody{{Allow: false}},
expectErr: true,
},
"fail/with options": {
ctl: &WebhookController{
client: http.DefaultClient,
webhooks: []*Webhook{{Name: "people", Kind: "AUTHORIZING"}},
options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(&x509.Certificate{
PublicKey: []byte("bad"),
})},
},
req: &webhook.RequestBody{},
responses: []*webhook.ResponseBody{{Allow: false}},
expectErr: true,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
@ -354,9 +267,6 @@ func TestWebhookController_Authorize(t *testing.T) {
if (err != nil) != test.expectErr {
t.Fatalf("Got err %v, want %v", err, test.expectErr)
}
if test.assertRequest != nil {
test.assertRequest(t, test.req)
}
})
}
}

View file

@ -15,7 +15,6 @@ import (
"go.step.sm/linkedca"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/webhook"
)
// x5cPayload extends jwt.Claims with step attributes.
@ -216,8 +215,7 @@ func (p *X5C) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro
// The X509 certificate will be available using the template variable
// AuthorizationCrt. For example {{ .AuthorizationCrt.DNSNames }} can be
// used to get all the domains.
x5cLeaf := claims.chains[0][0]
data.SetAuthorizationCertificate(x5cLeaf)
data.SetAuthorizationCertificate(claims.chains[0][0])
templateOptions, err := TemplateOptions(p.Options, data)
if err != nil {
@ -240,7 +238,7 @@ func (p *X5C) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro
newProvisionerExtensionOption(TypeX5C, p.Name, ""),
profileLimitDuration{
p.ctl.Claimer.DefaultTLSCertDuration(),
x5cLeaf.NotBefore, x5cLeaf.NotAfter,
claims.chains[0][0].NotBefore, claims.chains[0][0].NotAfter,
},
// validators
commonNameValidator(claims.Subject),
@ -248,12 +246,7 @@ func (p *X5C) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro
defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.ctl.getPolicy().getX509()),
p.ctl.newWebhookController(
data,
linkedca.Webhook_X509,
webhook.WithX5CCertificate(x5cLeaf),
webhook.WithAuthorizationPrincipal(x5cLeaf.Subject.CommonName),
),
p.ctl.newWebhookController(data, linkedca.Webhook_X509),
}, nil
}
@ -312,8 +305,7 @@ func (p *X5C) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
// The X509 certificate will be available using the template variable
// AuthorizationCrt. For example {{ .AuthorizationCrt.DNSNames }} can be
// used to get all the domains.
x5cLeaf := claims.chains[0][0]
data.SetAuthorizationCertificate(x5cLeaf)
data.SetAuthorizationCertificate(claims.chains[0][0])
templateOptions, err := TemplateSSHOptions(p.Options, data)
if err != nil {
@ -333,7 +325,7 @@ func (p *X5C) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
return append(signOptions,
p,
// Checks the validity bounds, and set the validity if has not been set.
&sshLimitDuration{p.ctl.Claimer, x5cLeaf.NotAfter},
&sshLimitDuration{p.ctl.Claimer, claims.chains[0][0].NotAfter},
// Validate public key.
&sshDefaultPublicKeyValidator{},
// Validate the validity period.
@ -343,11 +335,6 @@ func (p *X5C) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
// Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), p.ctl.getPolicy().getSSHUser()),
// Call webhooks
p.ctl.newWebhookController(
data,
linkedca.Webhook_SSH,
webhook.WithX5CCertificate(x5cLeaf),
webhook.WithAuthorizationPrincipal(x5cLeaf.Subject.CommonName),
),
p.ctl.newWebhookController(data, linkedca.Webhook_SSH),
), nil
}

View file

@ -12,7 +12,6 @@ import (
"go.step.sm/crypto/jose"
"go.step.sm/crypto/pemutil"
"go.step.sm/crypto/randutil"
"go.step.sm/linkedca"
"github.com/smallstep/assert"
"github.com/smallstep/certificates/api/render"
@ -498,8 +497,6 @@ func TestX5C_AuthorizeSign(t *testing.T) {
assert.Equals(t, nil, v.policyEngine)
case *WebhookController:
assert.Len(t, 0, v.webhooks)
assert.Equals(t, linkedca.Webhook_X509, v.certType)
assert.Len(t, 2, v.options)
default:
assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v))
}
@ -804,8 +801,6 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
case *sshDefaultPublicKeyValidator, *sshCertDefaultValidator, sshCertificateOptionsFunc:
case *WebhookController:
assert.Len(t, 0, v.webhooks)
assert.Equals(t, linkedca.Webhook_SSH, v.certType)
assert.Len(t, 2, v.options)
default:
assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v))
}

View file

@ -606,13 +606,7 @@ func doReload(ca *CA) error {
}
// Use same address in new server
newCA.srv.Addr = ca.srv.Addr
if err := ca.srv.Reload(newCA.srv); err != nil {
return err
}
// Wait a few ms until the http server calls listener.Accept()
time.Sleep(100 * time.Millisecond)
return nil
return ca.srv.Reload(newCA.srv)
}
func TestBootstrapListener(t *testing.T) {

16
go.mod
View file

@ -6,8 +6,6 @@ require (
cloud.google.com/go/longrunning v0.5.1
cloud.google.com/go/security v1.15.1
github.com/Masterminds/sprig/v3 v3.2.3
github.com/dgraph-io/badger v1.6.2
github.com/dgraph-io/badger/v2 v2.2007.4
github.com/fxamacker/cbor/v2 v2.4.0
github.com/go-chi/chi v4.1.2+incompatible
github.com/golang/mock v1.6.0
@ -32,18 +30,18 @@ require (
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
go.step.sm/cli-utils v0.7.6
go.step.sm/crypto v0.32.4
go.step.sm/linkedca v0.20.0
go.step.sm/linkedca v0.19.1
golang.org/x/crypto v0.11.0
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
golang.org/x/net v0.12.0
google.golang.org/api v0.132.0
google.golang.org/api v0.131.0
google.golang.org/grpc v1.56.2
google.golang.org/protobuf v1.31.0
gopkg.in/square/go-jose.v2 v2.6.0
)
require (
cloud.google.com/go v0.110.4 // indirect
cloud.google.com/go v0.110.2 // indirect
cloud.google.com/go/compute v1.20.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.0 // indirect
@ -66,6 +64,8 @@ require (
github.com/chzyer/readline v1.5.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
@ -134,9 +134,9 @@ require (
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.1.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

24
go.sum
View file

@ -31,8 +31,8 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD
cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk=
cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -1065,8 +1065,8 @@ go.step.sm/cli-utils v0.7.6 h1:YkpLVrepmy2c5+eaz/wduiGxlgrRx3YdAStE37if25g=
go.step.sm/cli-utils v0.7.6/go.mod h1:j+FxFZ2gbWkAJl0eded/rksuxmNqWpmyxbkXcukGJaY=
go.step.sm/crypto v0.32.4 h1:jSr5sB6vJCciqFB3BFKgK5ykRtuzKqdl4j9+CYkS8Hc=
go.step.sm/crypto v0.32.4/go.mod h1:A009Gtqx80nTz/9DreRMflMGgaSWTuhK8En6XycK9yA=
go.step.sm/linkedca v0.20.0 h1:bH41rvyDm3nSSJ5xgGsKUZOpzJcq5x2zacMIeqtq9oI=
go.step.sm/linkedca v0.20.0/go.mod h1:eybHw6ZTpuFmkUQnTBRWM2SPIGaP0VbYeo1bupfPT70=
go.step.sm/linkedca v0.19.1 h1:uY0ByT/uB3FCQ8zIo9mU7MWG7HKf5sDXNEBeN94MuP8=
go.step.sm/linkedca v0.19.1/go.mod h1:vPV2ad3LFQJmV7XWt87VlnJSs6UOqgsbVGVWe3veEmI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@ -1488,8 +1488,8 @@ google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtuk
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc=
google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0=
google.golang.org/api v0.131.0 h1:AcgWS2edQ4chVEt/SxgDKubVu/9/idCJy00tBGuGB4M=
google.golang.org/api v0.131.0/go.mod h1:7vtkbKv2REjJbxmHSkBTBQ5LUGvPdAqjjvt84XAfhpA=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1567,12 +1567,12 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y=
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU=
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs=
google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk=
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=

View file

@ -43,23 +43,8 @@ var (
"acme_external_account_keyID_reference_index",
"acme_external_account_keyID_provisionerID_index",
}
adminTables = []string{
"admins",
"provisioners",
"authority_policies",
}
)
type DB interface {
CreateTable([]byte) error
Set(bucket, key, value []byte) error
}
type dryRunDB struct{}
func (*dryRunDB) CreateTable([]byte) error { return nil }
func (*dryRunDB) Set(bucket, key, value []byte) error { return nil }
func usage(fs *flag.FlagSet) {
name := filepath.Base(os.Args[0])
fmt.Fprintf(os.Stderr, "%s is a tool to migrate data from BadgerDB to MySQL or PostgreSQL.\n", name)
@ -67,15 +52,14 @@ func usage(fs *flag.FlagSet) {
fmt.Fprintf(os.Stderr, " %s [-v1|-v2] -dir=<path> [-value-dir=<path>] -type=type -database=<source>\n", name)
fmt.Fprintln(os.Stderr, "\nExamples:")
fmt.Fprintf(os.Stderr, " %s -v1 -dir /var/lib/step-ca/db -type=mysql -database \"user@unix/step_ca\"\n", name)
fmt.Fprintf(os.Stderr, " %s -v1 -dir /var/lib/step-ca/db -type=mysql -database \"user:password@tcp(localhost:3306)/step_ca\"\n", name)
fmt.Fprintf(os.Stderr, " %s -v2 -dir /var/lib/step-ca/db -type=mysql -database \"user:password@tcp(localhost:3306)/step_ca\"\n", name)
fmt.Fprintf(os.Stderr, " %s -v2 -dir /var/lib/step-ca/db -type=postgresql -database \"user=postgres dbname=step_ca\"\n", name)
fmt.Fprintf(os.Stderr, " %s -v2 -dir /var/lib/step-ca/db -dry-run\"\n", name)
fmt.Fprintln(os.Stderr, "\nOptions:")
fs.PrintDefaults()
}
func main() {
var v1, v2, dryRun bool
var v1, v2 bool
var dir, valueDir string
var typ, database string
var key string
@ -83,13 +67,12 @@ func main() {
fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
fs.BoolVar(&v1, "v1", false, "use badger v1 as the source database")
fs.BoolVar(&v2, "v2", false, "use badger v2 as the source database")
fs.BoolVar(&v2, "v2", true, "use badger v2 as the source database")
fs.StringVar(&dir, "dir", "", "badger database directory")
fs.StringVar(&valueDir, "value-dir", "", "badger database value directory")
fs.StringVar(&typ, "type", "", "the destination database type to use")
fs.StringVar(&database, "database", "", "the destination driver-specific data source name")
fs.StringVar(&key, "key", "", "the key used to resume the migration")
fs.BoolVar(&dryRun, "dry-run", false, "runs the migration scripts without writing anything")
fs.Usage = func() { usage(fs) }
fs.Parse(os.Args[1:])
@ -98,9 +81,9 @@ func main() {
fatal("flag -v1 or -v2 are required")
case dir == "":
fatal("flag -dir is required")
case typ != "postgresql" && typ != "mysql" && !dryRun:
case typ != "postgresql" && typ != "mysql":
fatal(`flag -type must be "postgresql" or "mysql"`)
case database == "" && !dryRun:
case database == "":
fatal("flag --database required")
}
@ -127,19 +110,13 @@ func main() {
}
}
var db DB
if dryRun {
db = &dryRunDB{}
} else {
db, err = nosql.New(typ, database)
if err != nil {
fatal("error opening %s database: %v", typ, err)
}
db, err := nosql.New(typ, database)
if err != nil {
fatal("error opening %s database: %v", typ, err)
}
allTables := append([]string{}, authorityTables...)
allTables = append(allTables, acmeTables...)
allTables = append(allTables, adminTables...)
// Convert prefix names to badger key prefixes
badgerKeys := make([][]byte, len(allTables))

View file

@ -68,13 +68,6 @@ func WithAttestationData(data *AttestationData) RequestBodyOption {
}
}
func WithAuthorizationPrincipal(p string) RequestBodyOption {
return func(rb *RequestBody) error {
rb.AuthorizationPrincipal = p
return nil
}
}
func WithSSHCertificateRequest(cr sshutil.CertificateRequest) RequestBodyOption {
return func(rb *RequestBody) error {
rb.SSHCertificateRequest = &SSHCertificateRequest{
@ -102,23 +95,3 @@ func WithSSHCertificate(cert *sshutil.Certificate, certTpl *ssh.Certificate) Req
return nil
}
}
func WithX5CCertificate(leaf *x509.Certificate) RequestBodyOption {
return func(rb *RequestBody) error {
rb.X5CCertificate = &X5CCertificate{
Raw: leaf.Raw,
PublicKeyAlgorithm: leaf.PublicKeyAlgorithm.String(),
NotBefore: leaf.NotBefore,
NotAfter: leaf.NotAfter,
}
if leaf.PublicKey != nil {
key, err := x509.MarshalPKIXPublicKey(leaf.PublicKey)
if err != nil {
return err
}
rb.X5CCertificate.PublicKey = key
}
return nil
}
}

View file

@ -7,7 +7,6 @@ import (
"time"
"github.com/smallstep/assert"
"go.step.sm/crypto/keyutil"
"go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util"
"golang.org/x/crypto/ssh"
@ -17,15 +16,6 @@ func TestNewRequestBody(t *testing.T) {
t1 := time.Now()
t2 := t1.Add(time.Hour)
key, err := keyutil.GenerateDefaultSigner()
if err != nil {
t.Fatal(err)
}
keyBytes, err := x509.MarshalPKIXPublicKey(key.Public())
if err != nil {
t.Fatal(err)
}
type test struct {
options []RequestBodyOption
want *RequestBody
@ -113,40 +103,6 @@ func TestNewRequestBody(t *testing.T) {
},
wantErr: false,
},
"X5C Certificate": {
options: []RequestBodyOption{
WithX5CCertificate(&x509.Certificate{
Raw: []byte("some raw data"),
NotBefore: t1,
NotAfter: t2,
PublicKeyAlgorithm: x509.ECDSA,
PublicKey: key.Public(),
}),
},
want: &RequestBody{
X5CCertificate: &X5CCertificate{
Raw: []byte("some raw data"),
PublicKeyAlgorithm: "ECDSA",
NotBefore: t1,
NotAfter: t2,
PublicKey: keyBytes,
},
},
wantErr: false,
},
"fail/X5C Certificate": {
options: []RequestBodyOption{
WithX5CCertificate(&x509.Certificate{
Raw: []byte("some raw data"),
NotBefore: t1,
NotAfter: t2,
PublicKeyAlgorithm: x509.ECDSA,
PublicKey: []byte("fail"),
}),
},
want: nil,
wantErr: true,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {

View file

@ -56,17 +56,6 @@ type AttestationData struct {
PermanentIdentifier string `json:"permanentIdentifier"`
}
// X5CCertificate is the authorization certificate sent to webhook servers for
// enriching or authorizing webhooks when signing X509 or SSH certificates using
// the X5C provisioner.
type X5CCertificate struct {
Raw []byte `json:"raw"`
PublicKey []byte `json:"publicKey"`
PublicKeyAlgorithm string `json:"publicKeyAlgorithm"`
NotBefore time.Time `json:"notBefore"`
NotAfter time.Time `json:"notAfter"`
}
// RequestBody is the body sent to webhook servers.
type RequestBody struct {
Timestamp time.Time `json:"timestamp"`
@ -82,8 +71,4 @@ type RequestBody struct {
// Only set for SCEP challenge validation requests
SCEPChallenge string `json:"scepChallenge,omitempty"`
SCEPTransactionID string `json:"scepTransactionID,omitempty"`
// Only set for X5C provisioners
X5CCertificate *X5CCertificate `json:"x5cCertificate,omitempty"`
// Set for X5C, AWS, GCP, and Azure provisioners
AuthorizationPrincipal string `json:"authorizationPrincipal,omitempty"`
}