package api
import (
"fmt"
"time"
"github.com/mitchellh/mapstructure"
)
// CAConfig is the structure for the Connect CA configuration.
type CAConfig struct {
// Provider is the CA provider implementation to use.
Provider string
// Configuration is arbitrary configuration for the provider. This
// should only contain primitive values and containers (such as lists
// and maps).
Config map [ string ] interface { }
CreateIndex uint64
ModifyIndex uint64
}
// CommonCAProviderConfig is the common options available to all CA providers.
type CommonCAProviderConfig struct {
LeafCertTTL time . Duration
SkipValidate bool
CSRMaxPerSecond float32
CSRMaxConcurrent int
}
// ConsulCAProviderConfig is the config for the built-in Consul CA provider.
type ConsulCAProviderConfig struct {
CommonCAProviderConfig ` mapstructure:",squash" `
PrivateKey string
RootCert string
RotationPeriod time . Duration
}
// ParseConsulCAConfig takes a raw config map and returns a parsed
// ConsulCAProviderConfig.
func ParseConsulCAConfig ( raw map [ string ] interface { } ) ( * ConsulCAProviderConfig , error ) {
var config ConsulCAProviderConfig
decodeConf := & mapstructure . DecoderConfig {
DecodeHook : mapstructure . StringToTimeDurationHookFunc ( ) ,
Result : & config ,
WeaklyTypedInput : true ,
}
decoder , err := mapstructure . NewDecoder ( decodeConf )
if err != nil {
return nil , err
}
if err := decoder . Decode ( raw ) ; err != nil {
return nil , fmt . Errorf ( "error decoding config: %s" , err )
}
return & config , nil
}
// CARootList is the structure for the results of listing roots.
type CARootList struct {
ActiveRootID string
TrustDomain string
Roots [ ] * CARoot
}
// CARoot represents a root CA certificate that is trusted.
type CARoot struct {
// ID is a globally unique ID (UUID) representing this CA root.
ID string
// Name is a human-friendly name for this CA root. This value is
// opaque to Consul and is not used for anything internally.
Name string
// RootCertPEM is the PEM-encoded public certificate.
RootCertPEM string ` json:"RootCert" `
// Active is true if this is the current active CA. This must only
// be true for exactly one CA. For any method that modifies roots in the
// state store, tests should be written to verify that multiple roots
// cannot be active.
Active bool
CreateIndex uint64
ModifyIndex uint64
}
// LeafCert is a certificate that has been issued by a Connect CA.
type LeafCert struct {
// SerialNumber is the unique serial number for this certificate.
// This is encoded in standard hex separated by :.
SerialNumber string
// CertPEM and PrivateKeyPEM are the PEM-encoded certificate and private
// key for that cert, respectively. This should not be stored in the
// state store, but is present in the sign API response.
CertPEM string ` json:",omitempty" `
PrivateKeyPEM string ` json:",omitempty" `
// Service is the name of the service for which the cert was issued.
// ServiceURI is the cert URI value.
Service string
ServiceURI string
// ValidAfter and ValidBefore are the validity periods for the
// certificate.
ValidAfter time . Time
ValidBefore time . Time
CreateIndex uint64
ModifyIndex uint64
}
// CARoots queries the list of available roots.
func ( h * Connect ) CARoots ( q * QueryOptions ) ( * CARootList , * QueryMeta , error ) {
r := h . c . newRequest ( "GET" , "/v1/connect/ca/roots" )
r . setQueryOptions ( q )
rtt , resp , err := requireOK ( h . c . doRequest ( r ) )
if err != nil {
return nil , nil , err
}
defer resp . Body . Close ( )
qm := & QueryMeta { }
parseQueryMeta ( resp , qm )
qm . RequestTime = rtt
var out CARootList
if err := decodeBody ( resp , & out ) ; err != nil {
return nil , nil , err
}
return & out , qm , nil
}
// CAGetConfig returns the current CA configuration.
func ( h * Connect ) CAGetConfig ( q * QueryOptions ) ( * CAConfig , * QueryMeta , error ) {
r := h . c . newRequest ( "GET" , "/v1/connect/ca/configuration" )
r . setQueryOptions ( q )
rtt , resp , err := requireOK ( h . c . doRequest ( r ) )
if err != nil {
return nil , nil , err
}
defer resp . Body . Close ( )
qm := & QueryMeta { }
parseQueryMeta ( resp , qm )
qm . RequestTime = rtt
var out CAConfig
if err := decodeBody ( resp , & out ) ; err != nil {
return nil , nil , err
}
return & out , qm , nil
}
// CASetConfig sets the current CA configuration.
func ( h * Connect ) CASetConfig ( conf * CAConfig , q * WriteOptions ) ( * WriteMeta , error ) {
r := h . c . newRequest ( "PUT" , "/v1/connect/ca/configuration" )
r . setWriteOptions ( q )
r . obj = conf
rtt , resp , err := requireOK ( h . c . doRequest ( r ) )
if err != nil {
return nil , err
}
defer resp . Body . Close ( )
wm := & WriteMeta { }
wm . RequestTime = rtt
return wm , nil
}