forked from TrueCloudLab/certificates
Add full policy validation in API
This commit is contained in:
parent
ed231d29e2
commit
7104299119
6 changed files with 618 additions and 251 deletions
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/smallstep/certificates/api/render"
|
"github.com/smallstep/certificates/api/render"
|
||||||
"github.com/smallstep/certificates/authority"
|
"github.com/smallstep/certificates/authority"
|
||||||
"github.com/smallstep/certificates/authority/admin"
|
"github.com/smallstep/certificates/authority/admin"
|
||||||
|
"github.com/smallstep/certificates/authority/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type policyAdminResponderInterface interface {
|
type policyAdminResponderInterface interface {
|
||||||
|
@ -104,6 +105,11 @@ func (par *PolicyAdminResponder) CreateAuthorityPolicy(w http.ResponseWriter, r
|
||||||
|
|
||||||
newPolicy.Deduplicate()
|
newPolicy.Deduplicate()
|
||||||
|
|
||||||
|
if err := validatePolicy(newPolicy); err != nil {
|
||||||
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, err, "error validating authority policy"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
adm := linkedca.MustAdminFromContext(ctx)
|
adm := linkedca.MustAdminFromContext(ctx)
|
||||||
|
|
||||||
var createdPolicy *linkedca.Policy
|
var createdPolicy *linkedca.Policy
|
||||||
|
@ -149,6 +155,11 @@ func (par *PolicyAdminResponder) UpdateAuthorityPolicy(w http.ResponseWriter, r
|
||||||
|
|
||||||
newPolicy.Deduplicate()
|
newPolicy.Deduplicate()
|
||||||
|
|
||||||
|
if err := validatePolicy(newPolicy); err != nil {
|
||||||
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, err, "error validating authority policy"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
adm := linkedca.MustAdminFromContext(ctx)
|
adm := linkedca.MustAdminFromContext(ctx)
|
||||||
|
|
||||||
var updatedPolicy *linkedca.Policy
|
var updatedPolicy *linkedca.Policy
|
||||||
|
@ -239,6 +250,11 @@ func (par *PolicyAdminResponder) CreateProvisionerPolicy(w http.ResponseWriter,
|
||||||
|
|
||||||
newPolicy.Deduplicate()
|
newPolicy.Deduplicate()
|
||||||
|
|
||||||
|
if err := validatePolicy(newPolicy); err != nil {
|
||||||
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, err, "error validating provisioner policy"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
prov.Policy = newPolicy
|
prov.Policy = newPolicy
|
||||||
|
|
||||||
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
||||||
|
@ -278,6 +294,11 @@ func (par *PolicyAdminResponder) UpdateProvisionerPolicy(w http.ResponseWriter,
|
||||||
|
|
||||||
newPolicy.Deduplicate()
|
newPolicy.Deduplicate()
|
||||||
|
|
||||||
|
if err := validatePolicy(newPolicy); err != nil {
|
||||||
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, err, "error validating provisioner policy"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
prov.Policy = newPolicy
|
prov.Policy = newPolicy
|
||||||
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
if err := par.auth.UpdateProvisioner(ctx, prov); err != nil {
|
||||||
if isBadRequest(err) {
|
if isBadRequest(err) {
|
||||||
|
@ -364,6 +385,11 @@ func (par *PolicyAdminResponder) CreateACMEAccountPolicy(w http.ResponseWriter,
|
||||||
|
|
||||||
newPolicy.Deduplicate()
|
newPolicy.Deduplicate()
|
||||||
|
|
||||||
|
if err := validatePolicy(newPolicy); err != nil {
|
||||||
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, err, "error validating ACME EAK policy"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
eak.Policy = newPolicy
|
eak.Policy = newPolicy
|
||||||
|
|
||||||
acmeEAK := linkedEAKToCertificates(eak)
|
acmeEAK := linkedEAKToCertificates(eak)
|
||||||
|
@ -400,6 +426,11 @@ func (par *PolicyAdminResponder) UpdateACMEAccountPolicy(w http.ResponseWriter,
|
||||||
|
|
||||||
newPolicy.Deduplicate()
|
newPolicy.Deduplicate()
|
||||||
|
|
||||||
|
if err := validatePolicy(newPolicy); err != nil {
|
||||||
|
render.Error(w, admin.WrapError(admin.ErrorBadRequestType, err, "error validating ACME EAK policy"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
eak.Policy = newPolicy
|
eak.Policy = newPolicy
|
||||||
acmeEAK := linkedEAKToCertificates(eak)
|
acmeEAK := linkedEAKToCertificates(eak)
|
||||||
if err := par.acmeDB.UpdateExternalAccountKey(ctx, prov.GetId(), acmeEAK); err != nil {
|
if err := par.acmeDB.UpdateExternalAccountKey(ctx, prov.GetId(), acmeEAK); err != nil {
|
||||||
|
@ -455,3 +486,31 @@ func isBadRequest(err error) bool {
|
||||||
isPolicyError := errors.As(err, &pe)
|
isPolicyError := errors.As(err, &pe)
|
||||||
return isPolicyError && (pe.Typ == authority.AdminLockOut || pe.Typ == authority.EvaluationFailure || pe.Typ == authority.ConfigurationFailure)
|
return isPolicyError && (pe.Typ == authority.AdminLockOut || pe.Typ == authority.EvaluationFailure || pe.Typ == authority.ConfigurationFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validatePolicy(p *linkedca.Policy) error {
|
||||||
|
|
||||||
|
// convert the policy; return early if nil
|
||||||
|
options := policy.PolicyToCertificates(p)
|
||||||
|
if options == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Initialize a temporary x509 allow/deny policy engine
|
||||||
|
if _, err = policy.NewX509PolicyEngine(options.GetX509Options()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize a temporary SSH allow/deny policy engine for host certificates
|
||||||
|
if _, err = policy.NewSSHHostPolicyEngine(options.GetSSHOptions()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize a temporary SSH allow/deny policy engine for user certificates
|
||||||
|
if _, err = policy.NewSSHUserPolicyEngine(options.GetSSHOptions()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -343,6 +343,32 @@ func TestPolicyAdminResponder_CreateAuthorityPolicy(t *testing.T) {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail/validatePolicy": func(t *testing.T) test {
|
||||||
|
ctx := context.Background()
|
||||||
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "error validating authority policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)")
|
||||||
|
adminErr.Message = "error validating authority policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)"
|
||||||
|
body := []byte(`
|
||||||
|
{
|
||||||
|
"x509": {
|
||||||
|
"allow": {
|
||||||
|
"uris": [
|
||||||
|
"https://example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
auth: &mockAdminAuthority{
|
||||||
|
MockGetAuthorityPolicy: func(ctx context.Context) (*linkedca.Policy, error) {
|
||||||
|
return nil, admin.NewError(admin.ErrorNotFoundType, "not found")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: body,
|
||||||
|
err: adminErr,
|
||||||
|
statusCode: 400,
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail/CreateAuthorityPolicy-policy-admin-lockout-error": func(t *testing.T) test {
|
"fail/CreateAuthorityPolicy-policy-admin-lockout-error": func(t *testing.T) test {
|
||||||
adm := &linkedca.Admin{
|
adm := &linkedca.Admin{
|
||||||
Subject: "step",
|
Subject: "step",
|
||||||
|
@ -610,6 +636,39 @@ func TestPolicyAdminResponder_UpdateAuthorityPolicy(t *testing.T) {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail/validatePolicy": func(t *testing.T) test {
|
||||||
|
policy := &linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"*.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "error validating authority policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)")
|
||||||
|
adminErr.Message = "error validating authority policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)"
|
||||||
|
body := []byte(`
|
||||||
|
{
|
||||||
|
"x509": {
|
||||||
|
"allow": {
|
||||||
|
"uris": [
|
||||||
|
"https://example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
auth: &mockAdminAuthority{
|
||||||
|
MockGetAuthorityPolicy: func(ctx context.Context) (*linkedca.Policy, error) {
|
||||||
|
return policy, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: body,
|
||||||
|
err: adminErr,
|
||||||
|
statusCode: 400,
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail/UpdateAuthorityPolicy-policy-admin-lockout-error": func(t *testing.T) test {
|
"fail/UpdateAuthorityPolicy-policy-admin-lockout-error": func(t *testing.T) test {
|
||||||
adm := &linkedca.Admin{
|
adm := &linkedca.Admin{
|
||||||
Subject: "step",
|
Subject: "step",
|
||||||
|
@ -1174,6 +1233,35 @@ func TestPolicyAdminResponder_CreateProvisionerPolicy(t *testing.T) {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail/validatePolicy": func(t *testing.T) test {
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Name: "provName",
|
||||||
|
}
|
||||||
|
ctx := linkedca.NewContextWithProvisioner(context.Background(), prov)
|
||||||
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "error validating provisioner policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)")
|
||||||
|
adminErr.Message = "error validating provisioner policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)"
|
||||||
|
body := []byte(`
|
||||||
|
{
|
||||||
|
"x509": {
|
||||||
|
"allow": {
|
||||||
|
"uris": [
|
||||||
|
"https://example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
auth: &mockAdminAuthority{
|
||||||
|
MockGetAuthorityPolicy: func(ctx context.Context) (*linkedca.Policy, error) {
|
||||||
|
return nil, admin.NewError(admin.ErrorNotFoundType, "not found")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: body,
|
||||||
|
err: adminErr,
|
||||||
|
statusCode: 400,
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail/auth.UpdateProvisioner-policy-admin-lockout-error": func(t *testing.T) test {
|
"fail/auth.UpdateProvisioner-policy-admin-lockout-error": func(t *testing.T) test {
|
||||||
adm := &linkedca.Admin{
|
adm := &linkedca.Admin{
|
||||||
Subject: "step",
|
Subject: "step",
|
||||||
|
@ -1391,6 +1479,43 @@ func TestPolicyAdminResponder_UpdateProvisionerPolicy(t *testing.T) {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail/validatePolicy": func(t *testing.T) test {
|
||||||
|
policy := &linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"*.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Name: "provName",
|
||||||
|
Policy: policy,
|
||||||
|
}
|
||||||
|
ctx := linkedca.NewContextWithProvisioner(context.Background(), prov)
|
||||||
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "error validating provisioner policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)")
|
||||||
|
adminErr.Message = "error validating provisioner policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)"
|
||||||
|
body := []byte(`
|
||||||
|
{
|
||||||
|
"x509": {
|
||||||
|
"allow": {
|
||||||
|
"uris": [
|
||||||
|
"https://example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
auth: &mockAdminAuthority{
|
||||||
|
MockGetAuthorityPolicy: func(ctx context.Context) (*linkedca.Policy, error) {
|
||||||
|
return nil, admin.NewError(admin.ErrorNotFoundType, "not found")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: body,
|
||||||
|
err: adminErr,
|
||||||
|
statusCode: 400,
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail/auth.UpdateProvisioner-policy-admin-lockout-error": func(t *testing.T) test {
|
"fail/auth.UpdateProvisioner-policy-admin-lockout-error": func(t *testing.T) test {
|
||||||
adm := &linkedca.Admin{
|
adm := &linkedca.Admin{
|
||||||
Subject: "step",
|
Subject: "step",
|
||||||
|
@ -1916,6 +2041,34 @@ func TestPolicyAdminResponder_CreateACMEAccountPolicy(t *testing.T) {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail/validatePolicy": func(t *testing.T) test {
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Name: "provName",
|
||||||
|
}
|
||||||
|
eak := &linkedca.EABKey{
|
||||||
|
Id: "eakID",
|
||||||
|
}
|
||||||
|
ctx := linkedca.NewContextWithProvisioner(context.Background(), prov)
|
||||||
|
ctx = linkedca.NewContextWithExternalAccountKey(ctx, eak)
|
||||||
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "error validating ACME EAK policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)")
|
||||||
|
adminErr.Message = "error validating ACME EAK policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)"
|
||||||
|
body := []byte(`
|
||||||
|
{
|
||||||
|
"x509": {
|
||||||
|
"allow": {
|
||||||
|
"uris": [
|
||||||
|
"https://example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
body: body,
|
||||||
|
err: adminErr,
|
||||||
|
statusCode: 400,
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail/acmeDB.UpdateExternalAccountKey-error": func(t *testing.T) test {
|
"fail/acmeDB.UpdateExternalAccountKey-error": func(t *testing.T) test {
|
||||||
prov := &linkedca.Provisioner{
|
prov := &linkedca.Provisioner{
|
||||||
Id: "provID",
|
Id: "provID",
|
||||||
|
@ -2109,6 +2262,42 @@ func TestPolicyAdminResponder_UpdateACMEAccountPolicy(t *testing.T) {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail/validatePolicy": func(t *testing.T) test {
|
||||||
|
policy := &linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"*.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
prov := &linkedca.Provisioner{
|
||||||
|
Name: "provName",
|
||||||
|
}
|
||||||
|
eak := &linkedca.EABKey{
|
||||||
|
Id: "eakID",
|
||||||
|
Policy: policy,
|
||||||
|
}
|
||||||
|
ctx := linkedca.NewContextWithProvisioner(context.Background(), prov)
|
||||||
|
ctx = linkedca.NewContextWithExternalAccountKey(ctx, eak)
|
||||||
|
adminErr := admin.NewError(admin.ErrorBadRequestType, "error validating ACME EAK policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)")
|
||||||
|
adminErr.Message = "error validating ACME EAK policy: cannot parse permitted URI domain constraint \"https://example.com\": URI domain constraint \"https://example.com\" contains scheme (not supported yet)"
|
||||||
|
body := []byte(`
|
||||||
|
{
|
||||||
|
"x509": {
|
||||||
|
"allow": {
|
||||||
|
"uris": [
|
||||||
|
"https://example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
return test{
|
||||||
|
ctx: ctx,
|
||||||
|
body: body,
|
||||||
|
err: adminErr,
|
||||||
|
statusCode: 400,
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail/acmeDB.UpdateExternalAccountKey-error": func(t *testing.T) test {
|
"fail/acmeDB.UpdateExternalAccountKey-error": func(t *testing.T) test {
|
||||||
policy := &linkedca.Policy{
|
policy := &linkedca.Policy{
|
||||||
X509: &linkedca.X509Policy{
|
X509: &linkedca.X509Policy{
|
||||||
|
@ -2426,3 +2615,97 @@ func Test_isBadRequest(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_validatePolicy(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
p *linkedca.Policy
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil",
|
||||||
|
args: args{
|
||||||
|
p: nil,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "x509",
|
||||||
|
args: args{
|
||||||
|
p: &linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"**.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ssh user",
|
||||||
|
args: args{
|
||||||
|
p: &linkedca.Policy{
|
||||||
|
Ssh: &linkedca.SSHPolicy{
|
||||||
|
User: &linkedca.SSHUserPolicy{
|
||||||
|
Allow: &linkedca.SSHUserNames{
|
||||||
|
Emails: []string{"@@example.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ssh host",
|
||||||
|
args: args{
|
||||||
|
p: &linkedca.Policy{
|
||||||
|
Ssh: &linkedca.SSHPolicy{
|
||||||
|
Host: &linkedca.SSHHostPolicy{
|
||||||
|
Allow: &linkedca.SSHHostNames{
|
||||||
|
Dns: []string{"**.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ok",
|
||||||
|
args: args{
|
||||||
|
p: &linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"*.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Ssh: &linkedca.SSHPolicy{
|
||||||
|
User: &linkedca.SSHUserPolicy{
|
||||||
|
Allow: &linkedca.SSHUserNames{
|
||||||
|
Emails: []string{"@example.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Host: &linkedca.SSHHostPolicy{
|
||||||
|
Allow: &linkedca.SSHHostNames{
|
||||||
|
Dns: []string{"*.local"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := validatePolicy(tt.args.p); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("validatePolicy() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ func (a *Authority) checkProvisionerPolicy(ctx context.Context, currentAdmin *li
|
||||||
func (a *Authority) checkPolicy(ctx context.Context, currentAdmin *linkedca.Admin, otherAdmins []*linkedca.Admin, p *linkedca.Policy) error {
|
func (a *Authority) checkPolicy(ctx context.Context, currentAdmin *linkedca.Admin, otherAdmins []*linkedca.Admin, p *linkedca.Policy) error {
|
||||||
|
|
||||||
// convert the policy; return early if nil
|
// convert the policy; return early if nil
|
||||||
policyOptions := policyToCertificates(p)
|
policyOptions := authPolicy.PolicyToCertificates(p)
|
||||||
if policyOptions == nil {
|
if policyOptions == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ func (a *Authority) reloadPolicyEngines(ctx context.Context) error {
|
||||||
return fmt.Errorf("error getting policy to (re)load policy engines: %w", err)
|
return fmt.Errorf("error getting policy to (re)load policy engines: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
policyOptions = policyToCertificates(linkedPolicy)
|
policyOptions = authPolicy.PolicyToCertificates(linkedPolicy)
|
||||||
} else {
|
} else {
|
||||||
policyOptions = a.config.AuthorityConfig.Policy
|
policyOptions = a.config.AuthorityConfig.Policy
|
||||||
}
|
}
|
||||||
|
@ -256,116 +256,3 @@ func isAllowed(engine authPolicy.X509Policy, sans []string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func policyToCertificates(p *linkedca.Policy) *authPolicy.Options {
|
|
||||||
|
|
||||||
// return early
|
|
||||||
if p == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// return early if x509 nor SSH is set
|
|
||||||
if p.GetX509() == nil && p.GetSsh() == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := &authPolicy.Options{}
|
|
||||||
|
|
||||||
// fill x509 policy configuration
|
|
||||||
if x509 := p.GetX509(); x509 != nil {
|
|
||||||
opts.X509 = &authPolicy.X509PolicyOptions{}
|
|
||||||
if allow := x509.GetAllow(); allow != nil {
|
|
||||||
opts.X509.AllowedNames = &authPolicy.X509NameOptions{}
|
|
||||||
if allow.Dns != nil {
|
|
||||||
opts.X509.AllowedNames.DNSDomains = allow.Dns
|
|
||||||
}
|
|
||||||
if allow.Ips != nil {
|
|
||||||
opts.X509.AllowedNames.IPRanges = allow.Ips
|
|
||||||
}
|
|
||||||
if allow.Emails != nil {
|
|
||||||
opts.X509.AllowedNames.EmailAddresses = allow.Emails
|
|
||||||
}
|
|
||||||
if allow.Uris != nil {
|
|
||||||
opts.X509.AllowedNames.URIDomains = allow.Uris
|
|
||||||
}
|
|
||||||
if allow.CommonNames != nil {
|
|
||||||
opts.X509.AllowedNames.CommonNames = allow.CommonNames
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if deny := x509.GetDeny(); deny != nil {
|
|
||||||
opts.X509.DeniedNames = &authPolicy.X509NameOptions{}
|
|
||||||
if deny.Dns != nil {
|
|
||||||
opts.X509.DeniedNames.DNSDomains = deny.Dns
|
|
||||||
}
|
|
||||||
if deny.Ips != nil {
|
|
||||||
opts.X509.DeniedNames.IPRanges = deny.Ips
|
|
||||||
}
|
|
||||||
if deny.Emails != nil {
|
|
||||||
opts.X509.DeniedNames.EmailAddresses = deny.Emails
|
|
||||||
}
|
|
||||||
if deny.Uris != nil {
|
|
||||||
opts.X509.DeniedNames.URIDomains = deny.Uris
|
|
||||||
}
|
|
||||||
if deny.CommonNames != nil {
|
|
||||||
opts.X509.DeniedNames.CommonNames = deny.CommonNames
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.X509.AllowWildcardNames = x509.GetAllowWildcardNames()
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill ssh policy configuration
|
|
||||||
if ssh := p.GetSsh(); ssh != nil {
|
|
||||||
opts.SSH = &authPolicy.SSHPolicyOptions{}
|
|
||||||
if host := ssh.GetHost(); host != nil {
|
|
||||||
opts.SSH.Host = &authPolicy.SSHHostCertificateOptions{}
|
|
||||||
if allow := host.GetAllow(); allow != nil {
|
|
||||||
opts.SSH.Host.AllowedNames = &authPolicy.SSHNameOptions{}
|
|
||||||
if allow.Dns != nil {
|
|
||||||
opts.SSH.Host.AllowedNames.DNSDomains = allow.Dns
|
|
||||||
}
|
|
||||||
if allow.Ips != nil {
|
|
||||||
opts.SSH.Host.AllowedNames.IPRanges = allow.Ips
|
|
||||||
}
|
|
||||||
if allow.Principals != nil {
|
|
||||||
opts.SSH.Host.AllowedNames.Principals = allow.Principals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if deny := host.GetDeny(); deny != nil {
|
|
||||||
opts.SSH.Host.DeniedNames = &authPolicy.SSHNameOptions{}
|
|
||||||
if deny.Dns != nil {
|
|
||||||
opts.SSH.Host.DeniedNames.DNSDomains = deny.Dns
|
|
||||||
}
|
|
||||||
if deny.Ips != nil {
|
|
||||||
opts.SSH.Host.DeniedNames.IPRanges = deny.Ips
|
|
||||||
}
|
|
||||||
if deny.Principals != nil {
|
|
||||||
opts.SSH.Host.DeniedNames.Principals = deny.Principals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if user := ssh.GetUser(); user != nil {
|
|
||||||
opts.SSH.User = &authPolicy.SSHUserCertificateOptions{}
|
|
||||||
if allow := user.GetAllow(); allow != nil {
|
|
||||||
opts.SSH.User.AllowedNames = &authPolicy.SSHNameOptions{}
|
|
||||||
if allow.Emails != nil {
|
|
||||||
opts.SSH.User.AllowedNames.EmailAddresses = allow.Emails
|
|
||||||
}
|
|
||||||
if allow.Principals != nil {
|
|
||||||
opts.SSH.User.AllowedNames.Principals = allow.Principals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if deny := user.GetDeny(); deny != nil {
|
|
||||||
opts.SSH.User.DeniedNames = &authPolicy.SSHNameOptions{}
|
|
||||||
if deny.Emails != nil {
|
|
||||||
opts.SSH.User.DeniedNames.EmailAddresses = deny.Emails
|
|
||||||
}
|
|
||||||
if deny.Principals != nil {
|
|
||||||
opts.SSH.User.DeniedNames.Principals = deny.Principals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ package policy
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"go.step.sm/linkedca"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/policy"
|
"github.com/smallstep/certificates/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,10 +54,14 @@ func NewX509PolicyEngine(policyOptions X509PolicyOptionsInterface) (X509Policy,
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if configuration specifies that wildcard names are allowed
|
||||||
if policyOptions.AreWildcardNamesAllowed() {
|
if policyOptions.AreWildcardNamesAllowed() {
|
||||||
options = append(options, policy.WithAllowLiteralWildcardNames())
|
options = append(options, policy.WithAllowLiteralWildcardNames())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable subject common name verification by default
|
||||||
|
options = append(options, policy.WithSubjectCommonNameVerification())
|
||||||
|
|
||||||
return policy.New(options...)
|
return policy.New(options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,3 +141,116 @@ func newSSHPolicyEngine(policyOptions SSHPolicyOptionsInterface, typ sshPolicyEn
|
||||||
|
|
||||||
return policy.New(options...)
|
return policy.New(options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PolicyToCertificates(p *linkedca.Policy) *Options {
|
||||||
|
|
||||||
|
// return early
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// return early if x509 nor SSH is set
|
||||||
|
if p.GetX509() == nil && p.GetSsh() == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &Options{}
|
||||||
|
|
||||||
|
// fill x509 policy configuration
|
||||||
|
if x509 := p.GetX509(); x509 != nil {
|
||||||
|
opts.X509 = &X509PolicyOptions{}
|
||||||
|
if allow := x509.GetAllow(); allow != nil {
|
||||||
|
opts.X509.AllowedNames = &X509NameOptions{}
|
||||||
|
if allow.Dns != nil {
|
||||||
|
opts.X509.AllowedNames.DNSDomains = allow.Dns
|
||||||
|
}
|
||||||
|
if allow.Ips != nil {
|
||||||
|
opts.X509.AllowedNames.IPRanges = allow.Ips
|
||||||
|
}
|
||||||
|
if allow.Emails != nil {
|
||||||
|
opts.X509.AllowedNames.EmailAddresses = allow.Emails
|
||||||
|
}
|
||||||
|
if allow.Uris != nil {
|
||||||
|
opts.X509.AllowedNames.URIDomains = allow.Uris
|
||||||
|
}
|
||||||
|
if allow.CommonNames != nil {
|
||||||
|
opts.X509.AllowedNames.CommonNames = allow.CommonNames
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if deny := x509.GetDeny(); deny != nil {
|
||||||
|
opts.X509.DeniedNames = &X509NameOptions{}
|
||||||
|
if deny.Dns != nil {
|
||||||
|
opts.X509.DeniedNames.DNSDomains = deny.Dns
|
||||||
|
}
|
||||||
|
if deny.Ips != nil {
|
||||||
|
opts.X509.DeniedNames.IPRanges = deny.Ips
|
||||||
|
}
|
||||||
|
if deny.Emails != nil {
|
||||||
|
opts.X509.DeniedNames.EmailAddresses = deny.Emails
|
||||||
|
}
|
||||||
|
if deny.Uris != nil {
|
||||||
|
opts.X509.DeniedNames.URIDomains = deny.Uris
|
||||||
|
}
|
||||||
|
if deny.CommonNames != nil {
|
||||||
|
opts.X509.DeniedNames.CommonNames = deny.CommonNames
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.X509.AllowWildcardNames = x509.GetAllowWildcardNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill ssh policy configuration
|
||||||
|
if ssh := p.GetSsh(); ssh != nil {
|
||||||
|
opts.SSH = &SSHPolicyOptions{}
|
||||||
|
if host := ssh.GetHost(); host != nil {
|
||||||
|
opts.SSH.Host = &SSHHostCertificateOptions{}
|
||||||
|
if allow := host.GetAllow(); allow != nil {
|
||||||
|
opts.SSH.Host.AllowedNames = &SSHNameOptions{}
|
||||||
|
if allow.Dns != nil {
|
||||||
|
opts.SSH.Host.AllowedNames.DNSDomains = allow.Dns
|
||||||
|
}
|
||||||
|
if allow.Ips != nil {
|
||||||
|
opts.SSH.Host.AllowedNames.IPRanges = allow.Ips
|
||||||
|
}
|
||||||
|
if allow.Principals != nil {
|
||||||
|
opts.SSH.Host.AllowedNames.Principals = allow.Principals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if deny := host.GetDeny(); deny != nil {
|
||||||
|
opts.SSH.Host.DeniedNames = &SSHNameOptions{}
|
||||||
|
if deny.Dns != nil {
|
||||||
|
opts.SSH.Host.DeniedNames.DNSDomains = deny.Dns
|
||||||
|
}
|
||||||
|
if deny.Ips != nil {
|
||||||
|
opts.SSH.Host.DeniedNames.IPRanges = deny.Ips
|
||||||
|
}
|
||||||
|
if deny.Principals != nil {
|
||||||
|
opts.SSH.Host.DeniedNames.Principals = deny.Principals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if user := ssh.GetUser(); user != nil {
|
||||||
|
opts.SSH.User = &SSHUserCertificateOptions{}
|
||||||
|
if allow := user.GetAllow(); allow != nil {
|
||||||
|
opts.SSH.User.AllowedNames = &SSHNameOptions{}
|
||||||
|
if allow.Emails != nil {
|
||||||
|
opts.SSH.User.AllowedNames.EmailAddresses = allow.Emails
|
||||||
|
}
|
||||||
|
if allow.Principals != nil {
|
||||||
|
opts.SSH.User.AllowedNames.Principals = allow.Principals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if deny := user.GetDeny(); deny != nil {
|
||||||
|
opts.SSH.User.DeniedNames = &SSHNameOptions{}
|
||||||
|
if deny.Emails != nil {
|
||||||
|
opts.SSH.User.DeniedNames.EmailAddresses = deny.Emails
|
||||||
|
}
|
||||||
|
if deny.Principals != nil {
|
||||||
|
opts.SSH.User.DeniedNames.Principals = deny.Principals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
155
authority/policy/policy_test.go
Normal file
155
authority/policy/policy_test.go
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
|
"go.step.sm/linkedca"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPolicyToCertificates(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
policy *linkedca.Policy
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *Options
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil",
|
||||||
|
args: args{
|
||||||
|
policy: nil,
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no-policy",
|
||||||
|
args: args{
|
||||||
|
&linkedca.Policy{},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "partial-policy",
|
||||||
|
args: args{
|
||||||
|
&linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"*.local"},
|
||||||
|
},
|
||||||
|
AllowWildcardNames: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &Options{
|
||||||
|
X509: &X509PolicyOptions{
|
||||||
|
AllowedNames: &X509NameOptions{
|
||||||
|
DNSDomains: []string{"*.local"},
|
||||||
|
},
|
||||||
|
AllowWildcardNames: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "full-policy",
|
||||||
|
args: args{
|
||||||
|
&linkedca.Policy{
|
||||||
|
X509: &linkedca.X509Policy{
|
||||||
|
Allow: &linkedca.X509Names{
|
||||||
|
Dns: []string{"step"},
|
||||||
|
Ips: []string{"127.0.0.1/24"},
|
||||||
|
Emails: []string{"*.example.com"},
|
||||||
|
Uris: []string{"https://*.local"},
|
||||||
|
CommonNames: []string{"some name"},
|
||||||
|
},
|
||||||
|
Deny: &linkedca.X509Names{
|
||||||
|
Dns: []string{"bad"},
|
||||||
|
Ips: []string{"127.0.0.30"},
|
||||||
|
Emails: []string{"badhost.example.com"},
|
||||||
|
Uris: []string{"https://badhost.local"},
|
||||||
|
CommonNames: []string{"another name"},
|
||||||
|
},
|
||||||
|
AllowWildcardNames: true,
|
||||||
|
},
|
||||||
|
Ssh: &linkedca.SSHPolicy{
|
||||||
|
Host: &linkedca.SSHHostPolicy{
|
||||||
|
Allow: &linkedca.SSHHostNames{
|
||||||
|
Dns: []string{"*.localhost"},
|
||||||
|
Ips: []string{"127.0.0.1/24"},
|
||||||
|
Principals: []string{"user"},
|
||||||
|
},
|
||||||
|
Deny: &linkedca.SSHHostNames{
|
||||||
|
Dns: []string{"badhost.localhost"},
|
||||||
|
Ips: []string{"127.0.0.40"},
|
||||||
|
Principals: []string{"root"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
User: &linkedca.SSHUserPolicy{
|
||||||
|
Allow: &linkedca.SSHUserNames{
|
||||||
|
Emails: []string{"@work"},
|
||||||
|
Principals: []string{"user"},
|
||||||
|
},
|
||||||
|
Deny: &linkedca.SSHUserNames{
|
||||||
|
Emails: []string{"root@work"},
|
||||||
|
Principals: []string{"root"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &Options{
|
||||||
|
X509: &X509PolicyOptions{
|
||||||
|
AllowedNames: &X509NameOptions{
|
||||||
|
DNSDomains: []string{"step"},
|
||||||
|
IPRanges: []string{"127.0.0.1/24"},
|
||||||
|
EmailAddresses: []string{"*.example.com"},
|
||||||
|
URIDomains: []string{"https://*.local"},
|
||||||
|
CommonNames: []string{"some name"},
|
||||||
|
},
|
||||||
|
DeniedNames: &X509NameOptions{
|
||||||
|
DNSDomains: []string{"bad"},
|
||||||
|
IPRanges: []string{"127.0.0.30"},
|
||||||
|
EmailAddresses: []string{"badhost.example.com"},
|
||||||
|
URIDomains: []string{"https://badhost.local"},
|
||||||
|
CommonNames: []string{"another name"},
|
||||||
|
},
|
||||||
|
AllowWildcardNames: true,
|
||||||
|
},
|
||||||
|
SSH: &SSHPolicyOptions{
|
||||||
|
Host: &SSHHostCertificateOptions{
|
||||||
|
AllowedNames: &SSHNameOptions{
|
||||||
|
DNSDomains: []string{"*.localhost"},
|
||||||
|
IPRanges: []string{"127.0.0.1/24"},
|
||||||
|
Principals: []string{"user"},
|
||||||
|
},
|
||||||
|
DeniedNames: &SSHNameOptions{
|
||||||
|
DNSDomains: []string{"badhost.localhost"},
|
||||||
|
IPRanges: []string{"127.0.0.40"},
|
||||||
|
Principals: []string{"root"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
User: &SSHUserCertificateOptions{
|
||||||
|
AllowedNames: &SSHNameOptions{
|
||||||
|
EmailAddresses: []string{"@work"},
|
||||||
|
Principals: []string{"user"},
|
||||||
|
},
|
||||||
|
DeniedNames: &SSHNameOptions{
|
||||||
|
EmailAddresses: []string{"root@work"},
|
||||||
|
Principals: []string{"root"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := PolicyToCertificates(tt.args.policy)
|
||||||
|
if !cmp.Equal(tt.want, got) {
|
||||||
|
t.Errorf("policyToCertificates() diff=\n%s", cmp.Diff(tt.want, got))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"go.step.sm/linkedca"
|
"go.step.sm/linkedca"
|
||||||
|
@ -195,141 +194,6 @@ func TestAuthority_checkPolicy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_policyToCertificates(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
policy *linkedca.Policy
|
|
||||||
want *policy.Options
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "nil",
|
|
||||||
policy: nil,
|
|
||||||
want: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no-policy",
|
|
||||||
policy: &linkedca.Policy{},
|
|
||||||
want: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "partial-policy",
|
|
||||||
policy: &linkedca.Policy{
|
|
||||||
X509: &linkedca.X509Policy{
|
|
||||||
Allow: &linkedca.X509Names{
|
|
||||||
Dns: []string{"*.local"},
|
|
||||||
},
|
|
||||||
AllowWildcardNames: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: &policy.Options{
|
|
||||||
X509: &policy.X509PolicyOptions{
|
|
||||||
AllowedNames: &policy.X509NameOptions{
|
|
||||||
DNSDomains: []string{"*.local"},
|
|
||||||
},
|
|
||||||
AllowWildcardNames: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "full-policy",
|
|
||||||
policy: &linkedca.Policy{
|
|
||||||
X509: &linkedca.X509Policy{
|
|
||||||
Allow: &linkedca.X509Names{
|
|
||||||
Dns: []string{"step"},
|
|
||||||
Ips: []string{"127.0.0.1/24"},
|
|
||||||
Emails: []string{"*.example.com"},
|
|
||||||
Uris: []string{"https://*.local"},
|
|
||||||
CommonNames: []string{"some name"},
|
|
||||||
},
|
|
||||||
Deny: &linkedca.X509Names{
|
|
||||||
Dns: []string{"bad"},
|
|
||||||
Ips: []string{"127.0.0.30"},
|
|
||||||
Emails: []string{"badhost.example.com"},
|
|
||||||
Uris: []string{"https://badhost.local"},
|
|
||||||
CommonNames: []string{"another name"},
|
|
||||||
},
|
|
||||||
AllowWildcardNames: true,
|
|
||||||
},
|
|
||||||
Ssh: &linkedca.SSHPolicy{
|
|
||||||
Host: &linkedca.SSHHostPolicy{
|
|
||||||
Allow: &linkedca.SSHHostNames{
|
|
||||||
Dns: []string{"*.localhost"},
|
|
||||||
Ips: []string{"127.0.0.1/24"},
|
|
||||||
Principals: []string{"user"},
|
|
||||||
},
|
|
||||||
Deny: &linkedca.SSHHostNames{
|
|
||||||
Dns: []string{"badhost.localhost"},
|
|
||||||
Ips: []string{"127.0.0.40"},
|
|
||||||
Principals: []string{"root"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
User: &linkedca.SSHUserPolicy{
|
|
||||||
Allow: &linkedca.SSHUserNames{
|
|
||||||
Emails: []string{"@work"},
|
|
||||||
Principals: []string{"user"},
|
|
||||||
},
|
|
||||||
Deny: &linkedca.SSHUserNames{
|
|
||||||
Emails: []string{"root@work"},
|
|
||||||
Principals: []string{"root"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: &policy.Options{
|
|
||||||
X509: &policy.X509PolicyOptions{
|
|
||||||
AllowedNames: &policy.X509NameOptions{
|
|
||||||
DNSDomains: []string{"step"},
|
|
||||||
IPRanges: []string{"127.0.0.1/24"},
|
|
||||||
EmailAddresses: []string{"*.example.com"},
|
|
||||||
URIDomains: []string{"https://*.local"},
|
|
||||||
CommonNames: []string{"some name"},
|
|
||||||
},
|
|
||||||
DeniedNames: &policy.X509NameOptions{
|
|
||||||
DNSDomains: []string{"bad"},
|
|
||||||
IPRanges: []string{"127.0.0.30"},
|
|
||||||
EmailAddresses: []string{"badhost.example.com"},
|
|
||||||
URIDomains: []string{"https://badhost.local"},
|
|
||||||
CommonNames: []string{"another name"},
|
|
||||||
},
|
|
||||||
AllowWildcardNames: true,
|
|
||||||
},
|
|
||||||
SSH: &policy.SSHPolicyOptions{
|
|
||||||
Host: &policy.SSHHostCertificateOptions{
|
|
||||||
AllowedNames: &policy.SSHNameOptions{
|
|
||||||
DNSDomains: []string{"*.localhost"},
|
|
||||||
IPRanges: []string{"127.0.0.1/24"},
|
|
||||||
Principals: []string{"user"},
|
|
||||||
},
|
|
||||||
DeniedNames: &policy.SSHNameOptions{
|
|
||||||
DNSDomains: []string{"badhost.localhost"},
|
|
||||||
IPRanges: []string{"127.0.0.40"},
|
|
||||||
Principals: []string{"root"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
User: &policy.SSHUserCertificateOptions{
|
|
||||||
AllowedNames: &policy.SSHNameOptions{
|
|
||||||
EmailAddresses: []string{"@work"},
|
|
||||||
Principals: []string{"user"},
|
|
||||||
},
|
|
||||||
DeniedNames: &policy.SSHNameOptions{
|
|
||||||
EmailAddresses: []string{"root@work"},
|
|
||||||
Principals: []string{"root"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got := policyToCertificates(tt.policy)
|
|
||||||
if !cmp.Equal(tt.want, got) {
|
|
||||||
t.Errorf("policyToCertificates() diff=\n%s", cmp.Diff(tt.want, got))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustPolicyEngine(t *testing.T, options *policy.Options) *policy.Engine {
|
func mustPolicyEngine(t *testing.T, options *policy.Options) *policy.Engine {
|
||||||
engine, err := policy.New(options)
|
engine, err := policy.New(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue