2023-03-15 16:00:52 +00:00
/ * *
* Copyright ( c ) HashiCorp , Inc .
* SPDX - License - Identifier : MPL - 2.0
* /
2023-01-18 18:20:44 +00:00
import Model , { attr } from '@ember-data/model' ;
import { inject as service } from '@ember/service' ;
2023-01-24 19:32:17 +00:00
import { tracked } from '@glimmer/tracking' ;
2023-01-18 18:20:44 +00:00
import lazyCapabilities , { apiPath } from 'vault/macros/lazy-capabilities' ;
import { withFormFields } from 'vault/decorators/model-form-fields' ;
import { withModelValidations } from 'vault/decorators/model-validations' ;
const validations = {
type : [ { type : 'presence' , message : 'Type is required.' } ] ,
commonName : [ { type : 'presence' , message : 'Common name is required.' } ] ,
issuerName : [
{
validator ( model ) {
2023-03-31 21:47:23 +00:00
if (
( model . actionType === 'generate-root' || model . actionType === 'rotate-root' ) &&
model . issuerName === 'default'
)
return false ;
2023-01-18 18:20:44 +00:00
return true ;
} ,
2023-03-31 21:47:23 +00:00
message : ` Issuer name must be unique across all issuers and not be the reserved value 'default'. ` ,
2023-01-18 18:20:44 +00:00
} ,
] ,
} ;
2023-03-23 15:49:24 +00:00
/ * *
* This model maps to multiple PKI endpoints , specifically the ones that make up the
* configuration / create workflow . These endpoints also share a nontypical behavior in that
* a POST request to the endpoints don ' t necessarily result in a single entity created --
* depending on the inputs , some number of issuers , keys , and certificates can be created
* from the API .
* /
2023-01-18 18:20:44 +00:00
@ withModelValidations ( validations )
@ withFormFields ( )
export default class PkiActionModel extends Model {
@ service secretMountPath ;
2023-01-24 19:32:17 +00:00
@ tracked actionType ; // used to toggle between different form fields when creating configuration
2023-01-18 18:20:44 +00:00
/* actionType import */
@ attr ( 'string' ) pemBundle ;
2023-03-02 23:38:39 +00:00
// readonly attrs returned after importing
@ attr importedIssuers ;
@ attr importedKeys ;
@ attr mapping ;
2023-03-23 15:49:24 +00:00
@ attr ( 'string' , { readOnly : true , masked : true } ) certificate ;
2023-01-18 18:20:44 +00:00
/* actionType generate-root */
2023-03-31 21:47:23 +00:00
// readonly attrs returned right after root generation
@ attr serialNumber ;
@ attr ( 'string' , { label : 'Issuing CA' , readOnly : true , masked : true } ) issuingCa ;
@ attr keyName ;
// end of readonly
2023-01-18 18:20:44 +00:00
@ attr ( 'string' , {
possibleValues : [ 'exported' , 'internal' , 'existing' , 'kms' ] ,
noDefault : true ,
} )
type ;
2023-01-24 19:32:17 +00:00
@ attr ( 'string' ) issuerName ; // REQUIRED for generate-root actionType, cannot be "default"
2023-01-18 18:20:44 +00:00
@ attr ( 'string' ) keyName ; // cannot be "default"
@ attr ( 'string' , {
defaultValue : 'default' ,
label : 'Key reference' ,
} )
keyRef ; // type=existing only
@ attr ( 'string' ) commonName ; // REQUIRED
@ attr ( 'string' , {
label : 'Subject Alternative Names (SANs)' ,
2023-02-02 17:23:15 +00:00
editType : 'stringArray' ,
2023-01-18 18:20:44 +00:00
} )
2023-02-24 15:56:12 +00:00
altNames ;
2023-01-18 18:20:44 +00:00
@ attr ( 'string' , {
label : 'IP Subject Alternative Names (IP SANs)' ,
2023-02-02 17:23:15 +00:00
editType : 'stringArray' ,
2023-01-18 18:20:44 +00:00
} )
ipSans ;
@ attr ( 'string' , {
label : 'URI Subject Alternative Names (URI SANs)' ,
2023-02-02 17:23:15 +00:00
editType : 'stringArray' ,
2023-01-18 18:20:44 +00:00
} )
uriSans ;
@ attr ( 'string' , {
label : 'Other SANs' ,
2023-02-02 17:23:15 +00:00
editType : 'stringArray' ,
2023-01-18 18:20:44 +00:00
} )
otherSans ;
@ attr ( 'string' , {
defaultValue : 'pem' ,
possibleValues : [ 'pem' , 'der' , 'pem_bundle' ] ,
} )
format ;
@ attr ( 'string' , {
defaultValue : 'der' ,
possibleValues : [ 'der' , 'pkcs8' ] ,
} )
privateKeyFormat ;
@ attr ( 'string' , {
defaultValue : 'rsa' ,
possibleValues : [ 'rsa' , 'ed25519' , 'ec' ] ,
} )
keyType ;
@ attr ( 'string' , {
defaultValue : '0' ,
// options management happens in pki-key-parameters
} )
keyBits ;
@ attr ( 'number' , {
defaultValue : - 1 ,
} )
maxPathLength ;
@ attr ( 'boolean' , {
label : 'Exclude common name from SANs' ,
subText :
'If checked, the common name will not be included in DNS or Email Subject Alternate Names. This is useful if the CN is a human-readable identifier, not a hostname or email address.' ,
defaultValue : false ,
} )
excludeCnFromSans ;
@ attr ( 'string' , {
label : 'Permitted DNS domains' ,
} )
permittedDnsDomains ;
@ attr ( 'string' , {
label : 'Organizational Units (OU)' ,
2023-02-02 17:23:15 +00:00
subText :
'A list of allowed serial numbers to be requested during certificate issuance. Shell-style globbing is supported. If empty, custom-specified serial numbers will be forbidden.' ,
editType : 'stringArray' ,
2023-01-18 18:20:44 +00:00
} )
ou ;
2023-02-02 17:23:15 +00:00
@ attr ( { editType : 'stringArray' } ) organization ;
@ attr ( { editType : 'stringArray' } ) country ;
@ attr ( { editType : 'stringArray' } ) locality ;
@ attr ( { editType : 'stringArray' } ) province ;
@ attr ( { editType : 'stringArray' } ) streetAddress ;
@ attr ( { editType : 'stringArray' } ) postalCode ;
2023-01-18 18:20:44 +00:00
@ attr ( 'string' , {
2023-02-24 15:56:12 +00:00
subText :
"Specifies the requested Subject's named Serial Number value. This has no impact on the Certificate's serial number randomly generated by Vault." ,
2023-01-18 18:20:44 +00:00
} )
2023-03-31 21:47:23 +00:00
subjectSerialNumber ;
// this is different from the number (16:5e:a0...) randomly generated by Vault
// https://developer.hashicorp.com/vault/api-docs/secret/pki#serial_number
2023-01-18 18:20:44 +00:00
2023-01-24 19:32:17 +00:00
@ attr ( 'boolean' , {
subText : 'Whether to add a Basic Constraints extension with CA: true.' ,
} )
addBasicConstraints ;
2023-01-18 18:20:44 +00:00
@ attr ( {
label : 'Backdate validity' ,
detailsLabel : 'Issued certificate backdating' ,
helperTextDisabled : 'Vault will use the default value, 30s' ,
helperTextEnabled :
'Also called the not_before_duration property. Allows certificates to be valid for a certain time period before now. This is useful to correct clock misalignment on various systems when setting up your CA.' ,
editType : 'ttl' ,
defaultValue : '30s' ,
} )
notBeforeDuration ;
@ attr ( 'string' ) managedKeyName ;
@ attr ( 'string' , {
label : 'Managed key UUID' ,
} )
managedKeyId ;
@ attr ( {
label : 'Not valid after' ,
detailsLabel : 'Issued certificates expire after' ,
subText :
'The time after which this certificate will no longer be valid. This can be a TTL (a range of time from now) or a specific date.' ,
editType : 'yield' ,
} )
customTtl ;
@ attr ( 'string' ) ttl ;
@ attr ( 'date' ) notAfter ;
2023-03-23 15:49:24 +00:00
@ attr ( 'string' , { label : 'Issuer ID' , readOnly : true , detailLinkTo : 'issuers.issuer.details' } ) issuerId ; // returned from generate-root action
2023-01-23 19:36:34 +00:00
2023-01-25 19:37:20 +00:00
// For generating and signing a CSR
2023-02-10 18:05:57 +00:00
@ attr ( 'string' , { label : 'CSR' , masked : true } ) csr ;
2023-01-25 19:37:20 +00:00
@ attr caChain ;
2023-03-23 15:49:24 +00:00
@ attr ( 'string' , { label : 'Key ID' , detailLinkTo : 'keys.key.details' } ) keyId ;
2023-02-10 18:05:57 +00:00
@ attr ( 'string' , { masked : true } ) privateKey ;
@ attr ( 'string' ) privateKeyType ;
2023-01-25 19:37:20 +00:00
2023-01-18 18:20:44 +00:00
get backend ( ) {
return this . secretMountPath . currentPath ;
}
// To determine which endpoint the config adapter should use,
// we want to check capabilities on the newer endpoints (those
// prefixed with "issuers") and use the old path as fallback
// if user does not have permissions.
@ lazyCapabilities ( apiPath ` ${ 'backend' } /issuers/import/bundle ` , 'backend' ) importBundlePath ;
@ lazyCapabilities ( apiPath ` ${ 'backend' } /issuers/generate/root/ ${ 'type' } ` , 'backend' , 'type' )
generateIssuerRootPath ;
@ lazyCapabilities ( apiPath ` ${ 'backend' } /issuers/generate/intermediate/ ${ 'type' } ` , 'backend' , 'type' )
generateIssuerCsrPath ;
@ lazyCapabilities ( apiPath ` ${ 'backend' } /issuers/cross-sign ` , 'backend' ) crossSignPath ;
get canImportBundle ( ) {
return this . importBundlePath . get ( 'canCreate' ) === true ;
}
get canGenerateIssuerRoot ( ) {
return this . generateIssuerRootPath . get ( 'canCreate' ) === true ;
}
get canGenerateIssuerIntermediate ( ) {
return this . generateIssuerCsrPath . get ( 'canCreate' ) === true ;
}
get canCrossSign ( ) {
return this . crossSignPath . get ( 'canCreate' ) === true ;
}
}