teleport/lib/services/authority.go

302 lines
9.1 KiB
Go
Raw Normal View History

2016-12-28 00:39:43 +00:00
package services
import (
2016-12-28 01:28:46 +00:00
"encoding/json"
"fmt"
2016-12-28 23:50:32 +00:00
"github.com/gravitational/teleport/lib/defaults"
2016-12-28 01:28:46 +00:00
"github.com/gravitational/teleport/lib/utils"
2016-12-28 00:39:43 +00:00
"github.com/gravitational/trace"
2016-12-28 01:28:46 +00:00
"golang.org/x/crypto/ssh"
2016-12-28 00:39:43 +00:00
)
// CertAuthority is a host or user certificate authority that
// can check and if it has private key stored as well, sign it too
type CertAuthority interface {
2016-12-29 02:47:33 +00:00
// GetID returns certificate authority ID -
// combined type and name
GetID() CertAuthID
2016-12-28 00:39:43 +00:00
// GetName returns cert authority name
GetName() string
// GetType returns user or host certificate authority
2016-12-28 22:07:03 +00:00
GetType() CertAuthType
2016-12-28 00:39:43 +00:00
// GetClusterName returns cluster name this cert authority
// is associated with
GetClusterName() string
// GetCheckingKeys returns public keys to check signature
GetCheckingKeys() [][]byte
// GetRoles returns a list of roles assumed by users signed by this CA
2016-12-28 22:07:03 +00:00
GetRoles() []string
2016-12-28 00:39:43 +00:00
// FirstSigningKey returns first signing key or returns error if it's not here
FirstSigningKey() ([]byte, error)
2016-12-28 01:28:46 +00:00
// GetRawObject returns raw object data, used for migrations
GetRawObject() interface{}
2016-12-29 02:47:33 +00:00
// Check checks object for errors
Check() error
// SetSigningKeys sets signing keys
SetSigningKeys([][]byte) error
2016-12-28 00:39:43 +00:00
}
2016-12-29 20:23:58 +00:00
// CertAuthorityV2 is version 1 resource spec for Cert Authority
type CertAuthorityV2 struct {
2016-12-28 00:39:43 +00:00
// Kind is a resource kind
Kind string `json:"kind"`
// Version is version
Version string `json:"version"`
// Metadata is connector metadata
Metadata Metadata `json:"metadata"`
// Spec contains cert authority specification
2016-12-29 20:23:58 +00:00
Spec CertAuthoritySpecV2 `json:"spec"`
2016-12-28 01:28:46 +00:00
// rawObject is object that is raw object stored in DB
2016-12-28 22:07:03 +00:00
// without any conversions applied, used in migrations
2016-12-28 01:28:46 +00:00
rawObject interface{}
2016-12-28 00:39:43 +00:00
}
2016-12-29 02:47:33 +00:00
// SetSigningKeys sets signing keys
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) SetSigningKeys(keys [][]byte) error {
2016-12-29 02:47:33 +00:00
ca.Spec.SigningKeys = keys
return nil
}
// GetID returns certificate authority ID -
// combined type and name
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetID() CertAuthID {
2016-12-29 02:47:33 +00:00
return CertAuthID{Type: ca.Spec.Type, DomainName: ca.Metadata.Name}
}
2016-12-28 22:07:03 +00:00
// GetName returns cert authority name
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetName() string {
2016-12-28 22:07:03 +00:00
return ca.Metadata.Name
}
// GetType returns user or host certificate authority
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetType() CertAuthType {
2016-12-28 22:07:03 +00:00
return ca.Spec.Type
}
// GetClusterName returns cluster name this cert authority
// is associated with
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetClusterName() string {
2016-12-28 22:07:03 +00:00
return ca.Spec.ClusterName
}
// GetCheckingKeys returns public keys to check signature
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetCheckingKeys() [][]byte {
2016-12-28 22:07:03 +00:00
return ca.Spec.CheckingKeys
}
// GetRoles returns a list of roles assumed by users signed by this CA
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetRoles() []string {
2016-12-28 22:07:03 +00:00
return ca.Spec.Roles
}
// GetRawObject returns raw object data, used for migrations
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) GetRawObject() interface{} {
2016-12-28 22:07:03 +00:00
return ca.rawObject
}
2016-12-28 00:39:43 +00:00
// FirstSigningKey returns first signing key or returns error if it's not here
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) FirstSigningKey() ([]byte, error) {
2016-12-28 00:39:43 +00:00
if len(ca.Spec.SigningKeys) == 0 {
return nil, trace.NotFound("%v has no signing keys", ca.Metadata.Name)
}
return ca.Spec.SigningKeys[0], nil
}
// ID returns id (consisting of domain name and type) that
// identifies the authority this key belongs to
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) ID() *CertAuthID {
2016-12-28 00:39:43 +00:00
return &CertAuthID{DomainName: ca.Spec.ClusterName, Type: ca.Spec.Type}
}
// Checkers returns public keys that can be used to check cert authorities
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) Checkers() ([]ssh.PublicKey, error) {
2016-12-28 00:39:43 +00:00
out := make([]ssh.PublicKey, 0, len(ca.Spec.CheckingKeys))
for _, keyBytes := range ca.Spec.CheckingKeys {
key, _, _, _, err := ssh.ParseAuthorizedKey(keyBytes)
if err != nil {
return nil, trace.BadParameter("invalid authority public key (len=%d): %v", len(keyBytes), err)
}
out = append(out, key)
}
return out, nil
}
// Signers returns a list of signers that could be used to sign keys
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) Signers() ([]ssh.Signer, error) {
2016-12-28 00:39:43 +00:00
out := make([]ssh.Signer, 0, len(ca.Spec.SigningKeys))
for _, keyBytes := range ca.Spec.SigningKeys {
signer, err := ssh.ParsePrivateKey(keyBytes)
if err != nil {
return nil, trace.Wrap(err)
}
out = append(out, signer)
}
return out, nil
}
// Check checks if all passed parameters are valid
2016-12-29 20:23:58 +00:00
func (ca *CertAuthorityV2) Check() error {
2016-12-28 00:39:43 +00:00
err := ca.ID().Check()
if err != nil {
return trace.Wrap(err)
}
_, err = ca.Checkers()
if err != nil {
return trace.Wrap(err)
}
_, err = ca.Signers()
if err != nil {
return trace.Wrap(err)
}
return nil
}
2016-12-29 20:23:58 +00:00
// CertAuthoritySpecV2 is a host or user certificate authority that
2016-12-28 00:39:43 +00:00
// can check and if it has private key stored as well, sign it too
2016-12-29 20:23:58 +00:00
type CertAuthoritySpecV2 struct {
2016-12-28 00:39:43 +00:00
// Type is either user or host certificate authority
Type CertAuthType `json:"type"`
// ClusterName identifies cluster name this authority serves,
// for host authorities that means base hostname of all servers,
// for user authorities that means organization name
ClusterName string `json:"cluster_name"`
// Checkers is a list of SSH public keys that can be used to check
// certificate signatures
CheckingKeys [][]byte `json:"checking_keys"`
// SigningKeys is a list of private keys used for signing
SigningKeys [][]byte `json:"signing_keys"`
// Roles is a list of roles assumed by users signed by this CA
2016-12-29 02:47:33 +00:00
Roles []string `json:"roles,omitempty"`
2016-12-28 00:39:43 +00:00
}
2016-12-29 20:23:58 +00:00
// CertAuthoritySpecV2Schema is JSON schema for cert authority V2
const CertAuthoritySpecV2Schema = `{
2016-12-28 00:39:43 +00:00
"type": "object",
"additionalProperties": false,
"required": ["type", "cluster_name", "checking_keys", "signing_keys"],
"properties": {
"type": {"type": "string"},
"cluster_name": {"type": "string"},
"checking_keys": {
"type": "array",
"items": {
2016-12-29 02:47:33 +00:00
"type": "string"
2016-12-28 00:39:43 +00:00
}
},
"signing_keys": {
"type": "array",
"items": {
2016-12-29 02:47:33 +00:00
"type": "string"
2016-12-28 00:39:43 +00:00
}
},
"roles": {
"type": "array",
"items": {
"type": "string"
}
}
}
}`
// CertAuthorityV0 is a host or user certificate authority that
// can check and if it has private key stored as well, sign it too
type CertAuthorityV0 struct {
// Type is either user or host certificate authority
Type CertAuthType `json:"type"`
// DomainName identifies domain name this authority serves,
// for host authorities that means base hostname of all servers,
// for user authorities that means organization name
DomainName string `json:"domain_name"`
// Checkers is a list of SSH public keys that can be used to check
// certificate signatures
CheckingKeys [][]byte `json:"checking_keys"`
// SigningKeys is a list of private keys used for signing
SigningKeys [][]byte `json:"signing_keys"`
// AllowedLogins is a list of allowed logins for users within
// this certificate authority
AllowedLogins []string `json:"allowed_logins"`
}
2016-12-28 01:28:46 +00:00
2016-12-29 20:23:58 +00:00
func (c *CertAuthorityV0) V2() *CertAuthorityV2 {
return &CertAuthorityV2{
2016-12-28 01:28:46 +00:00
Kind: KindCertAuthority,
2016-12-29 20:23:58 +00:00
Version: V2,
2016-12-28 01:28:46 +00:00
Metadata: Metadata{
2016-12-28 23:50:32 +00:00
Name: c.DomainName,
Namespace: defaults.Namespace,
2016-12-28 01:28:46 +00:00
},
2016-12-29 20:23:58 +00:00
Spec: CertAuthoritySpecV2{
2016-12-28 01:28:46 +00:00
Type: c.Type,
ClusterName: c.DomainName,
CheckingKeys: c.CheckingKeys,
SigningKeys: c.SigningKeys,
},
rawObject: *c,
}
}
var certAuthorityMarshaler CertAuthorityMarshaler = &TeleportCertAuthorityMarshaler{}
// SetCertAuthorityMarshaler sets global user marshaler
func SetCertAuthorityMarshaler(u CertAuthorityMarshaler) {
marshalerMutex.Lock()
defer marshalerMutex.Unlock()
certAuthorityMarshaler = u
}
// GetCertAuthorityMarshaler returns currently set user marshaler
func GetCertAuthorityMarshaler() CertAuthorityMarshaler {
marshalerMutex.RLock()
defer marshalerMutex.RUnlock()
return certAuthorityMarshaler
}
// CertAuthorityMarshaler implements marshal/unmarshal of User implementations
// mostly adds support for extended versions
type CertAuthorityMarshaler interface {
// UnmarshalCertAuthority unmarhsals cert authority from binary representation
2016-12-28 22:07:03 +00:00
UnmarshalCertAuthority(bytes []byte) (CertAuthority, error)
2016-12-28 01:28:46 +00:00
// MarshalCertAuthority to binary representation
MarshalCertAuthority(c CertAuthority) ([]byte, error)
}
// GetCertAuthoritySchema returns JSON Schema for cert authorities
func GetCertAuthoritySchema() string {
2016-12-29 20:23:58 +00:00
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, CertAuthoritySpecV2Schema)
2016-12-28 01:28:46 +00:00
}
type TeleportCertAuthorityMarshaler struct{}
// UnmarshalUser unmarshals user from JSON
2016-12-28 22:07:03 +00:00
func (*TeleportCertAuthorityMarshaler) UnmarshalCertAuthority(bytes []byte) (CertAuthority, error) {
2016-12-28 01:28:46 +00:00
var h ResourceHeader
err := json.Unmarshal(bytes, &h)
if err != nil {
return nil, trace.Wrap(err)
}
switch h.Version {
case "":
var ca CertAuthorityV0
err := json.Unmarshal(bytes, &ca)
if err != nil {
return nil, trace.Wrap(err)
}
2016-12-29 20:23:58 +00:00
return ca.V2(), nil
case V2:
var ca CertAuthorityV2
2016-12-28 01:28:46 +00:00
if err := utils.UnmarshalWithSchema(GetCertAuthoritySchema(), &ca, bytes); err != nil {
return nil, trace.BadParameter(err.Error())
}
2016-12-29 02:54:10 +00:00
return &ca, nil
2016-12-28 01:28:46 +00:00
}
2016-12-29 02:54:10 +00:00
return nil, trace.BadParameter("cert authority resource version %v is not supported", h.Version)
2016-12-28 01:28:46 +00:00
}
// MarshalUser marshalls cert authority into JSON
func (*TeleportCertAuthorityMarshaler) MarshalCertAuthority(ca CertAuthority) ([]byte, error) {
2016-12-28 22:07:03 +00:00
return json.Marshal(ca)
2016-12-28 01:28:46 +00:00
}