Don't show field names when not needed

This commit is contained in:
Jeff Mitchell
2015-09-29 16:13:54 -07:00
parent 55fc4ba898
commit 667d5cafd3
4 changed files with 336 additions and 258 deletions

View File

@@ -37,8 +37,9 @@ func Backend() *framework.Backend {
Paths: []*framework.Path{ Paths: []*framework.Path{
pathRoles(&b), pathRoles(&b),
pathGenerateCA(&b), pathGenerateRootCA(&b),
pathSignCA(&b), pathGenerateIntermediateCA(&b),
pathSignIntermediateCA(&b),
pathSetCA(&b), pathSetCA(&b),
pathConfigCA(&b), pathConfigCA(&b),
pathConfigCRL(&b), pathConfigCRL(&b),

View File

@@ -170,10 +170,16 @@ func validateCommonNames(req *logical.Request, commonNames []string, role *roleE
func generateCert(b *backend, func generateCert(b *backend,
role *roleEntry, role *roleEntry,
signingBundle *certutil.ParsedCertBundle, signingBundle *certutil.ParsedCertBundle,
isCA bool,
req *logical.Request, req *logical.Request,
data *framework.FieldData) (*certutil.ParsedCertBundle, error) { data *framework.FieldData) (*certutil.ParsedCertBundle, error) {
creationBundle, err := generateCreationBundle(b, role, signingBundle, req, data) _, ok := data.GetOk("common_name")
if !ok {
return nil, certutil.UserError{Err: "The common_name field is required"}
}
creationBundle, err := generateCreationBundle(b, role, signingBundle, isCA, req, data)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -189,10 +195,11 @@ func generateCert(b *backend,
func generateCSR(b *backend, func generateCSR(b *backend,
role *roleEntry, role *roleEntry,
signingBundle *certutil.ParsedCertBundle, signingBundle *certutil.ParsedCertBundle,
isCA bool,
req *logical.Request, req *logical.Request,
data *framework.FieldData) (*certutil.ParsedCSRBundle, error) { data *framework.FieldData) (*certutil.ParsedCSRBundle, error) {
creationBundle, err := generateCreationBundle(b, role, signingBundle, req, data) creationBundle, err := generateCreationBundle(b, role, signingBundle, isCA, req, data)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -209,10 +216,16 @@ func signCert(b *backend,
role *roleEntry, role *roleEntry,
signingBundle *certutil.ParsedCertBundle, signingBundle *certutil.ParsedCertBundle,
csr *x509.CertificateRequest, csr *x509.CertificateRequest,
isCA bool,
req *logical.Request, req *logical.Request,
data *framework.FieldData) (*certutil.ParsedCertBundle, error) { data *framework.FieldData) (*certutil.ParsedCertBundle, error) {
creationBundle, err := generateCreationBundle(b, role, signingBundle, req, data) _, ok := data.GetOk("common_name")
if !ok {
return nil, certutil.UserError{Err: "The common_name field is required"}
}
creationBundle, err := generateCreationBundle(b, role, signingBundle, isCA, req, data)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -228,47 +241,56 @@ func signCert(b *backend,
func generateCreationBundle(b *backend, func generateCreationBundle(b *backend,
role *roleEntry, role *roleEntry,
signingBundle *certutil.ParsedCertBundle, signingBundle *certutil.ParsedCertBundle,
isCA bool,
req *logical.Request, req *logical.Request,
data *framework.FieldData) (*certCreationBundle, error) { data *framework.FieldData) (*certCreationBundle, error) {
var err error var err error
// Get the common name(s) // Get the common name(s)
var commonNames []string var cn string
cn := data.Get("common_name").(string) cnInt, ok := data.GetOk("common_name")
if len(cn) == 0 { if ok {
return nil, certutil.UserError{Err: "The common_name field is required"} cn = cnInt.(string)
} }
commonNames = []string{cn}
cnAlt := data.Get("alt_names").(string) commonNames := []string{cn}
if len(cnAlt) != 0 { cnAltInt, ok := data.GetOk("alt_names")
for _, v := range strings.Split(cnAlt, ",") { if ok {
commonNames = append(commonNames, v) cnAlt := cnAltInt.(string)
if len(cnAlt) != 0 {
for _, v := range strings.Split(cnAlt, ",") {
commonNames = append(commonNames, v)
}
} }
} }
// Get any IP SANs // Get any IP SANs
ipSANs := []net.IP{} ipSANs := []net.IP{}
ipAltInt, ok := data.GetOk("ip_sans")
ipAlt := data.Get("ip_sans").(string) if ok {
if len(ipAlt) != 0 { ipAlt := ipAltInt.(string)
if !role.AllowIPSANs { if len(ipAlt) != 0 {
return nil, certutil.UserError{Err: fmt.Sprintf( if !role.AllowIPSANs {
"IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)}
}
for _, v := range strings.Split(ipAlt, ",") {
parsedIP := net.ParseIP(v)
if parsedIP == nil {
return nil, certutil.UserError{Err: fmt.Sprintf( return nil, certutil.UserError{Err: fmt.Sprintf(
"the value '%s' is not a valid IP address", v)} "IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)}
}
for _, v := range strings.Split(ipAlt, ",") {
parsedIP := net.ParseIP(v)
if parsedIP == nil {
return nil, certutil.UserError{Err: fmt.Sprintf(
"the value '%s' is not a valid IP address", v)}
}
ipSANs = append(ipSANs, parsedIP)
} }
ipSANs = append(ipSANs, parsedIP)
} }
} }
ttlField := data.Get("ttl").(string) var ttlField string
if len(ttlField) == 0 { ttlFieldInt, ok := data.GetOk("ttl")
if !ok {
ttlField = role.TTL ttlField = role.TTL
} else {
ttlField = ttlFieldInt.(string)
} }
var ttl time.Duration var ttl time.Duration
@@ -340,11 +362,13 @@ func generateCreationBundle(b *backend,
Usage: usage, Usage: usage,
} }
if _, ok := req.Data["ca_type"]; ok { if isCA {
creationBundle.CAType = req.Data["ca_type"].(string) if _, ok := req.Data["ca_type"]; ok {
} creationBundle.CAType = req.Data["ca_type"].(string)
if _, ok := req.Data["pki_address"]; ok { }
creationBundle.PKIAddress = req.Data["pki_address"].(string) if _, ok := req.Data["pki_address"]; ok {
creationBundle.PKIAddress = req.Data["pki_address"].(string)
}
} }
return creationBundle, nil return creationBundle, nil

View File

@@ -14,43 +14,7 @@ import (
"github.com/hashicorp/vault/logical/framework" "github.com/hashicorp/vault/logical/framework"
) )
var generateAndSignSchema = map[string]*framework.FieldSchema{ var rootAndSignSchema = map[string]*framework.FieldSchema{
"type": &framework.FieldSchema{
Type: framework.TypeString,
Description: `Must be "self-signed" or "intermediate".
If set to "self-signed", a self-signed root CA
will be generated. If set to "intermediate", a
CSR will be returned for signing by the root.`,
},
"exported": &framework.FieldSchema{
Type: framework.TypeString,
Description: `Must be "internal" or "exported".
If set to "exported", the generated private
key will be returned. This is your *only*
chance to retrieve the private key!`,
},
"pki_address": &framework.FieldSchema{
Type: framework.TypeString,
Description: `The base URL of the PKI mount. For
"self-signed"; this is needed when
calling '/generate/' and should be
the base URL of the mount where you
are running this command, e.g.
"https://vault.example.com/v1/root_pki".
For "intermediate", this is needed
when calling '/sign/' and should be
the base URL of the destination
mount of the certificate, e.g.
"https://vault.example.com/v1/intermediate_pki".
For HA setups, the given host name
should be the address that can always
be used to contact the leader. This is
is used for generating the CA/CRL URLs in
the certificate. Required as specified.`,
},
"common_name": &framework.FieldSchema{ "common_name": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The requested common name; if you want more than Description: `The requested common name; if you want more than
@@ -70,26 +34,16 @@ in a comma-delimited list`,
common-delimited list`, common-delimited list`,
}, },
"key_bits": &framework.FieldSchema{
Type: framework.TypeInt,
Default: 2048,
Description: `The number of bits to use. You will almost
certainly want to change this if you adjust
the key_type.`,
},
"ttl": &framework.FieldSchema{ "ttl": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The requested Time To Live for the certificate; Description: `The requested Time To Live for the certificate;
sets the expiration date. If not specified sets the expiration date. If not specified
the role default, backend default, or system the role default, backend default, or system
default TTL is used, in that order. Cannot default TTL is used, in that order. Cannot
be larger than the mount max TTL.`, be larger than the mount max TTL. Note:
}, this only has an effect when generating
a CA cert or signing a CA cert, not when
"csr": &framework.FieldSchema{ creating a CSR for an intermediate CA.`,
Type: framework.TypeString,
Description: `PEM-format CSR to be signed.`,
}, },
} }
@@ -134,26 +88,88 @@ endpoint, just the signed certificate.`,
} }
} }
func pathGenerateCA(b *backend) *framework.Path { func pathGenerateRootCA(b *backend) *framework.Path {
return &framework.Path{ ret := &framework.Path{
Pattern: "config/ca/generate/" + framework.GenericNameRegex("type") + "/" + framework.GenericNameRegex("exported"), Pattern: "config/ca/generate/root/" + framework.GenericNameRegex("exported"),
Fields: generateAndSignSchema, Fields: rootAndSignSchema,
Callbacks: map[logical.Operation]framework.OperationFunc{ Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathCAGenerateWrite, logical.WriteOperation: b.pathCAGenerateRoot,
}, },
HelpSynopsis: pathConfigCAGenerateHelpSyn, HelpSynopsis: pathConfigCAGenerateHelpSyn,
HelpDescription: pathConfigCAGenerateHelpDesc, HelpDescription: pathConfigCAGenerateHelpDesc,
} }
ret.Fields["pki_address"] = &framework.FieldSchema{
Type: framework.TypeString,
Description: `The base URL of the PKI mount, e.g.
"https://vault.example.com/v1/root_pki".
For HA setups, the given host name
should be the address that can always
be used to contact the leader, as this is
is used for generating the CA/CRL URLs in
the certificate.`,
}
ret.Fields["exported"] = &framework.FieldSchema{
Type: framework.TypeString,
Description: `Must be "internal" or "exported".
If set to "exported", the generated private
key will be returned. This is your *only*
chance to retrieve the private key!`,
}
ret.Fields["key_bits"] = &framework.FieldSchema{
Type: framework.TypeInt,
Default: 2048,
Description: `The number of bits to use. You will almost
certainly want to change this if you adjust
the key_type.`,
}
return ret
} }
func pathSignCA(b *backend) *framework.Path { func pathGenerateIntermediateCA(b *backend) *framework.Path {
return &framework.Path{ ret := &framework.Path{
Pattern: "config/ca/generate/intermediate/" + framework.GenericNameRegex("exported"),
Fields: map[string]*framework.FieldSchema{},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathCAGenerateIntermediate,
},
HelpSynopsis: pathConfigCAGenerateHelpSyn,
HelpDescription: pathConfigCAGenerateHelpDesc,
}
ret.Fields["exported"] = &framework.FieldSchema{
Type: framework.TypeString,
Description: `Must be "internal" or "exported".
If set to "exported", the generated private
key will be returned. This is your *only*
chance to retrieve the private key!`,
}
ret.Fields["key_bits"] = &framework.FieldSchema{
Type: framework.TypeInt,
Default: 2048,
Description: `The number of bits to use. You will almost
certainly want to change this if you adjust
the key_type.`,
}
return ret
}
func pathSignIntermediateCA(b *backend) *framework.Path {
ret := &framework.Path{
Pattern: "config/ca/sign", Pattern: "config/ca/sign",
Fields: generateAndSignSchema, Fields: rootAndSignSchema,
Callbacks: map[logical.Operation]framework.OperationFunc{ Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathCASignWrite, logical.WriteOperation: b.pathCASignWrite,
@@ -162,9 +178,28 @@ func pathSignCA(b *backend) *framework.Path {
HelpSynopsis: pathConfigCASignHelpSyn, HelpSynopsis: pathConfigCASignHelpSyn,
HelpDescription: pathConfigCASignHelpDesc, HelpDescription: pathConfigCASignHelpDesc,
} }
ret.Fields["pki_address"] = &framework.FieldSchema{
Type: framework.TypeString,
Description: `The base URL of the *destination*
PKI mount, e.g.
"https://vault.example.com/v1/intermediate_pki".
For HA setups, the given host name
should be the address that can always
be used to contact the leader, as this is
is used for generating the CA/CRL URLs in
the certificate.`,
}
ret.Fields["csr"] = &framework.FieldSchema{
Type: framework.TypeString,
Description: `PEM-format CSR to be signed.`,
}
return ret
} }
func (b *backend) pathCAGenerateWrite( func (b *backend) pathCAGenerateRoot(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) { req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
var err error var err error
exported := data.Get("exported").(string) exported := data.Get("exported").(string)
@@ -176,39 +211,28 @@ func (b *backend) pathCAGenerateWrite(
"The \"exported\" path parameter must be \"internal\" or \"exported\"")), nil "The \"exported\" path parameter must be \"internal\" or \"exported\"")), nil
} }
genType := data.Get("type").(string) req.Data["ca_type"] = "root"
switch genType {
case "self-signed": pkiAddress := strings.ToLower(data.Get("pki_address").(string))
case "intermediate": switch {
default: case len(pkiAddress) == 0:
return logical.ErrorResponse(fmt.Sprintf( return logical.ErrorResponse(fmt.Sprintf(
"The \"type\" path parameter must be \"self-signed\" or \"intermediate\"")), nil "\"pki_address\" cannot be empty")), nil
case !strings.HasPrefix(pkiAddress, "http"):
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" must be a URL")), nil
case !strings.Contains(pkiAddress, "/v1/"):
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" needs to be the path to the PKI mount, not the base Vault path")), nil
case !strings.Contains(pkiAddress, "/v1/"+req.MountPoint[:len(req.MountPoint)-1]):
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" needs to be the path to this mount")), nil
}
if strings.HasSuffix(pkiAddress, "/") {
pkiAddress = pkiAddress[:len(pkiAddress)-1]
} }
req.Data["ca_type"] = genType req.Data["pki_address"] = pkiAddress
if genType == "self-signed" {
pkiAddress := strings.ToLower(data.Get("pki_address").(string))
switch {
case len(pkiAddress) == 0:
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" cannot be empty")), nil
case !strings.HasPrefix(pkiAddress, "http"):
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" must be a URL")), nil
case !strings.Contains(pkiAddress, "/v1/"):
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" needs to be the path to the PKI mount, not the base Vault path")), nil
case !strings.Contains(pkiAddress, "/v1/"+req.MountPoint[:len(req.MountPoint)-1]):
return logical.ErrorResponse(fmt.Sprintf(
"\"pki_address\" needs to be the path to this mount")), nil
}
if strings.HasSuffix(pkiAddress, "/") {
pkiAddress = pkiAddress[:len(pkiAddress)-1]
}
req.Data["pki_address"] = pkiAddress
}
role := &roleEntry{ role := &roleEntry{
TTL: data.Get("ttl").(string), TTL: data.Get("ttl").(string),
@@ -219,21 +243,6 @@ func (b *backend) pathCAGenerateWrite(
EnforceHostnames: false, EnforceHostnames: false,
} }
maxSystemTTL := b.System().MaxLeaseTTL()
ttl := b.System().DefaultLeaseTTL()
if len(role.TTL) != 0 {
ttl, err = time.ParseDuration(role.TTL)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf(
"Invalid ttl: %s", err)), nil
}
}
if ttl > maxSystemTTL {
return logical.ErrorResponse(fmt.Sprintf(
"\"ttl\" value must be less than mount max of %d seconds", maxSystemTTL/time.Second)), nil
}
switch role.KeyBits { switch role.KeyBits {
case 0: case 0:
role.KeyBits = 2048 role.KeyBits = 2048
@@ -246,105 +255,135 @@ func (b *backend) pathCAGenerateWrite(
} }
var resp *logical.Response var resp *logical.Response
switch genType { parsedBundle, err := generateCert(b, role, nil, true, req, data)
case "self-signed": if err != nil {
parsedBundle, err := generateCert(b, role, nil, req, data) switch err.(type) {
if err != nil { case certutil.UserError:
switch err.(type) { return logical.ErrorResponse(err.Error()), nil
case certutil.UserError: case certutil.InternalError:
return logical.ErrorResponse(err.Error()), nil
case certutil.InternalError:
return nil, err
}
}
cb, err := parsedBundle.ToCertBundle()
if err != nil {
return nil, fmt.Errorf("Error converting raw cert bundle to cert bundle: %s", err)
}
resp = &logical.Response{
Data: map[string]interface{}{
"serial_number": cb.SerialNumber,
"certificate": cb.Certificate,
"issuing_ca": cb.IssuingCA,
"expiration": int(parsedBundle.Certificate.NotAfter.Unix()),
},
}
if exported == "exported" {
resp.Data["private_key"] = cb.PrivateKey
resp.Data["private_key_type"] = cb.PrivateKeyType
}
entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
if err != nil {
return nil, err
}
err = req.Storage.Put(entry)
if err != nil {
return nil, err return nil, err
} }
}
// For ease of later use, also store just the certificate at a known cb, err := parsedBundle.ToCertBundle()
// location, plus a blank CRL if err != nil {
entry.Key = "ca" return nil, fmt.Errorf("Error converting raw cert bundle to cert bundle: %s", err)
entry.Value = parsedBundle.CertificateBytes }
err = req.Storage.Put(entry)
if err != nil {
return nil, err
}
entry.Key = "crl" resp = &logical.Response{
entry.Value = []byte{} Data: map[string]interface{}{
err = req.Storage.Put(entry) "serial_number": cb.SerialNumber,
if err != nil { "certificate": cb.Certificate,
return nil, err "issuing_ca": cb.IssuingCA,
} "expiration": int(parsedBundle.Certificate.NotAfter.Unix()),
},
}
case "intermediate": if exported == "exported" {
parsedBundle, err := generateCSR(b, role, nil, req, data) resp.Data["private_key"] = cb.PrivateKey
if err != nil { resp.Data["private_key_type"] = cb.PrivateKeyType
switch err.(type) { }
case certutil.UserError:
return logical.ErrorResponse(err.Error()), nil
case certutil.InternalError:
return nil, err
}
}
csrb, err := parsedBundle.ToCSRBundle() entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error converting raw CSR bundle to CSR bundle: %s", err) return nil, err
} }
err = req.Storage.Put(entry)
if err != nil {
return nil, err
}
resp = &logical.Response{ // For ease of later use, also store just the certificate at a known
Data: map[string]interface{}{ // location, plus a blank CRL
"csr": csrb.CSR, entry.Key = "ca"
}, entry.Value = parsedBundle.CertificateBytes
} err = req.Storage.Put(entry)
if err != nil {
return nil, err
}
if exported == "exported" { entry.Key = "crl"
resp.Data["private_key"] = csrb.PrivateKey entry.Value = []byte{}
resp.Data["private_key_type"] = csrb.PrivateKeyType err = req.Storage.Put(entry)
} if err != nil {
return nil, err
}
cb := &certutil.CertBundle{ return resp, nil
PrivateKey: csrb.PrivateKey, }
PrivateKeyType: csrb.PrivateKeyType,
}
entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
if err != nil {
return nil, err
}
err = req.Storage.Put(entry)
if err != nil {
return nil, err
}
func (b *backend) pathCAGenerateIntermediate(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
var err error
exported := data.Get("exported").(string)
switch exported {
case "exported":
case "internal":
default: default:
return logical.ErrorResponse("Unknown generation type"), nil return logical.ErrorResponse(fmt.Sprintf(
"The \"exported\" path parameter must be \"internal\" or \"exported\"")), nil
}
req.Data["ca_type"] = "intermediate"
role := &roleEntry{
KeyType: "rsa",
KeyBits: data.Get("key_bits").(int),
AllowLocalhost: true,
AllowAnyName: true,
EnforceHostnames: false,
}
switch role.KeyBits {
case 0:
role.KeyBits = 2048
case 1024:
case 2048:
case 4096:
default:
return logical.ErrorResponse(fmt.Sprintf(
"\"key_bits\" must be 1024, 2048, or 4096")), nil
}
var resp *logical.Response
parsedBundle, err := generateCSR(b, role, nil, true, req, data)
if err != nil {
switch err.(type) {
case certutil.UserError:
return logical.ErrorResponse(err.Error()), nil
case certutil.InternalError:
return nil, err
}
}
csrb, err := parsedBundle.ToCSRBundle()
if err != nil {
return nil, fmt.Errorf("Error converting raw CSR bundle to CSR bundle: %s", err)
}
resp = &logical.Response{
Data: map[string]interface{}{
"csr": csrb.CSR,
},
}
if exported == "exported" {
resp.Data["private_key"] = csrb.PrivateKey
resp.Data["private_key_type"] = csrb.PrivateKeyType
}
cb := &certutil.CertBundle{
PrivateKey: csrb.PrivateKey,
PrivateKeyType: csrb.PrivateKeyType,
}
entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
if err != nil {
return nil, err
}
err = req.Storage.Put(entry)
if err != nil {
return nil, err
} }
return resp, nil return resp, nil
@@ -425,7 +464,7 @@ func (b *backend) pathCASignWrite(
"Error fetching CA certificate: %s", caErr)} "Error fetching CA certificate: %s", caErr)}
} }
parsedBundle, err := signCert(b, role, signingBundle, csr, req, data) parsedBundle, err := signCert(b, role, signingBundle, csr, true, req, data)
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case certutil.UserError: case certutil.UserError:

View File

@@ -10,45 +10,65 @@ import (
"github.com/hashicorp/vault/logical/framework" "github.com/hashicorp/vault/logical/framework"
) )
func pathIssue(b *backend) *framework.Path { var issueAndSignSchema = map[string]*framework.FieldSchema{
return &framework.Path{ "role": &framework.FieldSchema{
Pattern: "issue/" + framework.GenericNameRegex("role"), Type: framework.TypeString,
Fields: map[string]*framework.FieldSchema{ Description: `The desired role with configuration for this
"role": &framework.FieldSchema{
Type: framework.TypeString,
Description: `The desired role with configuration for this
request`, request`,
}, },
"common_name": &framework.FieldSchema{ "common_name": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The requested common name; if you want more than Description: `The requested common name; if you want more than
one, specify the alternative names in the one, specify the alternative names in the
alt_names map`, alt_names map`,
}, },
"alt_names": &framework.FieldSchema{ "alt_names": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The requested Subject Alternative Names, if any, Description: `The requested Subject Alternative Names, if any,
in a comma-delimited list`, in a comma-delimited list`,
}, },
"ip_sans": &framework.FieldSchema{ "ip_sans": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The requested IP SANs, if any, in a Description: `The requested IP SANs, if any, in a
common-delimited list`, common-delimited list`,
}, },
"ttl": &framework.FieldSchema{ "ttl": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: `The requested Time To Live for the certificate; Description: `The requested Time To Live for the certificate;
sets the expiration date. If not specified sets the expiration date. If not specified
the role default, backend default, or system the role default, backend default, or system
default TTL is used, in that order. Cannot default TTL is used, in that order. Cannot
be later than the role max TTL.`, be later than the role max TTL.`,
}, },
"csr": &framework.FieldSchema{
Type: framework.TypeString,
Description: `PEM-format CSR to be signed.`,
},
}
func pathIssue(b *backend) *framework.Path {
return &framework.Path{
Pattern: "issue/" + framework.GenericNameRegex("role"),
Fields: issueAndSignSchema,
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathIssueCert,
}, },
HelpSynopsis: pathIssueCertHelpSyn,
HelpDescription: pathIssueCertHelpDesc,
}
}
func pathSign(b *backend) *framework.Path {
return &framework.Path{
Pattern: "sign/" + framework.GenericNameRegex("role"),
Fields: issueAndSignSchema,
Callbacks: map[logical.Operation]framework.OperationFunc{ Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathIssueCert, logical.WriteOperation: b.pathIssueCert,
}, },
@@ -82,13 +102,7 @@ func (b *backend) pathIssueCert(
"Error fetching CA certificate: %s", caErr)} "Error fetching CA certificate: %s", caErr)}
} }
// Don't allow these on the standard path. Ideally we should determine parsedBundle, err := generateCert(b, role, signingBundle, false, req, data)
// this internally once we get SudoPrivilege from System() working
// for non-TokenStore
delete(req.Data, "ca_type")
delete(req.Data, "pki_address")
parsedBundle, err := generateCert(b, role, signingBundle, req, data)
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case certutil.UserError: case certutil.UserError: