Add working implementation of the linkedca.

Replaces the authority adminDB with a new impmentation that users the
linkedca client to retrieve the data.

Note that this implementation still hardcodes the endpoint to localhost.
This commit is contained in:
Mariano Cano 2021-07-12 18:11:00 +02:00
parent 49c1427d15
commit dd9850ce4c
2 changed files with 182 additions and 4 deletions

View file

@ -442,10 +442,17 @@ func (a *Authority) init() error {
// Initialize step-ca Admin Database if it's not already initialized using // Initialize step-ca Admin Database if it's not already initialized using
// WithAdminDB. // WithAdminDB.
if a.adminDB == nil { if a.adminDB == nil {
// Check if AuthConfig already exists if a.config.AuthorityConfig.AuthorityID == "" {
a.adminDB, err = adminDBNosql.New(a.db.(nosql.DB), admin.DefaultAuthorityID) // Check if AuthConfig already exists
if err != nil { a.adminDB, err = adminDBNosql.New(a.db.(nosql.DB), admin.DefaultAuthorityID)
return err if err != nil {
return err
}
} else {
a.adminDB, err = createLinkedCAClient(a.config.AuthorityConfig.AuthorityID, "localhost:6040")
if err != nil {
return err
}
} }
} }

171
authority/linkedca.go Normal file
View file

@ -0,0 +1,171 @@
package authority
import (
"context"
"crypto/tls"
"crypto/x509"
"io/ioutil"
"path/filepath"
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"go.step.sm/cli-utils/config"
"go.step.sm/linkedca"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
type linkedCaClient struct {
client linkedca.MajordomoClient
authorityID string
}
func createLinkedCAClient(authorityID, endpoint string) (*linkedCaClient, error) {
base := filepath.Join(config.StepPath(), "linkedca")
rootFile := filepath.Join(base, "root_ca.crt")
certFile := filepath.Join(base, "linkedca.crt")
keyFile := filepath.Join(base, "linkedca.key")
b, err := ioutil.ReadFile(rootFile)
if err != nil {
return nil, errors.Wrap(err, "error reading linkedca root")
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(b) {
return nil, errors.Errorf("error reading %s: no certificates were found", rootFile)
}
conn, err := grpc.Dial(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
RootCAs: pool,
GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, errors.Wrap(err, "error reading linkedca certificate")
}
return &cert, nil
},
})))
if err != nil {
return nil, errors.Wrapf(err, "error connecting %s", endpoint)
}
return &linkedCaClient{
client: linkedca.NewMajordomoClient(conn),
authorityID: authorityID,
}, nil
}
func (c *linkedCaClient) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
resp, err := c.client.CreateProvisioner(ctx, &linkedca.CreateProvisionerRequest{
Type: prov.Type,
Name: prov.Name,
Details: prov.Details,
Claims: prov.Claims,
X509Template: prov.X509Template,
SshTemplate: prov.SshTemplate,
})
if err != nil {
return errors.Wrap(err, "error creating provisioner")
}
prov.Id = resp.Id
prov.AuthorityId = resp.AuthorityId
return nil
}
func (c *linkedCaClient) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error) {
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
AuthorityId: c.authorityID,
})
if err != nil {
return nil, errors.Wrap(err, "error getting provisioners")
}
for _, p := range resp.Provisioners {
if p.Id == id {
return p, nil
}
}
return nil, errs.NotFound("provisioner not found")
}
func (c *linkedCaClient) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
AuthorityId: c.authorityID,
})
if err != nil {
return nil, errors.Wrap(err, "error getting provisioners")
}
return resp.Provisioners, nil
}
func (c *linkedCaClient) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
_, err := c.client.UpdateProvisioner(ctx, &linkedca.UpdateProvisionerRequest{
Id: prov.Id,
Name: prov.Name,
Details: prov.Details,
Claims: prov.Claims,
X509Template: prov.X509Template,
SshTemplate: prov.SshTemplate,
})
return errors.Wrap(err, "error updating provisioner")
}
func (c *linkedCaClient) DeleteProvisioner(ctx context.Context, id string) error {
_, err := c.client.DeleteProvisioner(ctx, &linkedca.DeleteProvisionerRequest{
Id: id,
})
return errors.Wrap(err, "error deleting provisioner")
}
func (c *linkedCaClient) CreateAdmin(ctx context.Context, adm *linkedca.Admin) error {
resp, err := c.client.CreateAdmin(ctx, &linkedca.CreateAdminRequest{
Subject: adm.Subject,
ProvisionerId: adm.ProvisionerId,
Type: adm.Type,
})
if err != nil {
return errors.Wrap(err, "error creating admin")
}
adm.Id = resp.Id
adm.AuthorityId = resp.AuthorityId
return nil
}
func (c *linkedCaClient) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) {
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
AuthorityId: c.authorityID,
})
if err != nil {
return nil, errors.Wrap(err, "error getting admins")
}
for _, a := range resp.Admins {
if a.Id == id {
return a, nil
}
}
return nil, errs.NotFound("admin not found")
}
func (c *linkedCaClient) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
AuthorityId: c.authorityID,
})
if err != nil {
return nil, errors.Wrap(err, "error getting admins")
}
return resp.Admins, nil
}
func (c *linkedCaClient) UpdateAdmin(ctx context.Context, adm *linkedca.Admin) error {
_, err := c.client.UpdateAdmin(ctx, &linkedca.UpdateAdminRequest{
Id: adm.Id,
Type: adm.Type,
})
return errors.Wrap(err, "error updating admin")
}
func (c *linkedCaClient) DeleteAdmin(ctx context.Context, id string) error {
_, err := c.client.DeleteAdmin(ctx, &linkedca.DeleteAdminRequest{
Id: id,
})
return errors.Wrap(err, "error deleting admin")
}