diff --git a/CHANGELOG.md b/CHANGELOG.md index 42a0d6439..9aa9e7b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,15 +15,21 @@ IMPROVEMENTS: * AliCloud Agent Support: Vault Agent can now authenticate against the AliCloud auth method. + * UI: Enable AliCloud auth method and Azure secrets engine via the UI. BUG FIXES: * core: Properly check error return from random byte reading [GH-5277] * core: Re-add `sys/` top-route injection for now [GH-5241] + * core: Properly store the replication checkpoint file if it's larger than the + storage engine's per-item limit * secrets/database: Fix nil pointer when revoking some leases [GH-5262] * secrets/pki: Fix sign-verbatim losing extra Subject attributes [GH-5245] * secrets/pki: Remove certificates from store when tidying revoked - certificates [GH-5231] + certificates and simplify API [GH-5231] + * ui: JSON editor will not coerce input to an object, and will now show an + error about Vault expecting an object [GH-5271] + ## 0.11.0 (August 28th, 2018) diff --git a/builtin/logical/pki/ca_test.go b/builtin/logical/pki/ca_test.go index 342272b49..66d666a5a 100644 --- a/builtin/logical/pki/ca_test.go +++ b/builtin/logical/pki/ca_test.go @@ -82,7 +82,7 @@ func TestBackend_CA_Steps(t *testing.T) { NotBefore: time.Now().Add(-30 * time.Second), NotAfter: time.Now().Add(262980 * time.Hour), BasicConstraintsValid: true, - IsCA: true, + IsCA: true, } caBytes, err := x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, cak.Public(), cak) if err != nil { @@ -107,7 +107,7 @@ func TestBackend_CA_Steps(t *testing.T) { if err != nil { panic(err) } - subjKeyID, err = certutil.GetSubjKeyID(rak) + _, err = certutil.GetSubjKeyID(rak) if err != nil { panic(err) } @@ -437,6 +437,7 @@ func runSteps(t *testing.T, rootB, intB *backend, client *api.Client, rootName, } verifyRevocation := func(t *testing.T, serial string, shouldFind bool) { + t.Helper() // Verify it is now revoked { resp, err := client.Logical().Read(rootName + "cert/" + intSerialNumber) diff --git a/builtin/logical/pki/path_tidy.go b/builtin/logical/pki/path_tidy.go index e1ec9d47f..e70473576 100644 --- a/builtin/logical/pki/path_tidy.go +++ b/builtin/logical/pki/path_tidy.go @@ -23,6 +23,11 @@ func pathTidy(b *backend) *framework.Path { the certificate store`, }, + "tidy_revocation_list": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `Deprecated; synonym for 'tidy_revoked_certs`, + }, + "tidy_revoked_certs": &framework.FieldSchema{ Type: framework.TypeBool, Description: `Set to true to expire all revoked @@ -54,6 +59,7 @@ func (b *backend) pathTidyWrite(ctx context.Context, req *logical.Request, d *fr safetyBuffer := d.Get("safety_buffer").(int) tidyCertStore := d.Get("tidy_cert_store").(bool) tidyRevokedCerts := d.Get("tidy_revoked_certs").(bool) + tidyRevocationList := d.Get("tidy_revocation_list").(bool) if safetyBuffer < 1 { return logical.ErrorResponse("safety_buffer must be greater than zero"), nil @@ -121,7 +127,7 @@ func (b *backend) pathTidyWrite(ctx context.Context, req *logical.Request, d *fr } } - if tidyRevokedCerts { + if tidyRevokedCerts || tidyRevocationList { b.revokeStorageLock.Lock() defer b.revokeStorageLock.Unlock() diff --git a/ui/app/components/mount-backend-form.js b/ui/app/components/mount-backend-form.js index 4c0abbb04..54de0825b 100644 --- a/ui/app/components/mount-backend-form.js +++ b/ui/app/components/mount-backend-form.js @@ -62,8 +62,11 @@ export default Component.extend({ getConfigModelType(methodType) { let mountType = this.get('mountType'); - let noConfig = ['approle']; - if (mountType === 'secret' || noConfig.includes(methodType)) { + // will be something like secret-aws + // or auth-azure + let key = `${mountType}-${methodType}`; + let noConfig = ['auth-approle', 'auth-alicloud']; + if (mountType === 'secret' || noConfig.includes(key)) { return; } if (methodType === 'aws') { diff --git a/ui/app/components/secret-edit.js b/ui/app/components/secret-edit.js index ff115506a..8d673dc7b 100644 --- a/ui/app/components/secret-edit.js +++ b/ui/app/components/secret-edit.js @@ -30,6 +30,7 @@ export default Ember.Component.extend(FocusOnInsertMixin, { // use a named action here so we don't have to pass one in // this will bubble to the route toggleAdvancedEdit: 'toggleAdvancedEdit', + error: null, codemirrorString: null, @@ -79,7 +80,8 @@ export default Ember.Component.extend(FocusOnInsertMixin, { 'key.isFolder', 'key.isError', 'key.flagsIsInvalid', - 'hasLintError' + 'hasLintError', + 'error' ), basicModeDisabled: computed('secretDataIsAdvanced', 'showAdvancedMode', function() { @@ -242,10 +244,15 @@ export default Ember.Component.extend(FocusOnInsertMixin, { }, codemirrorUpdated(val, codemirror) { + this.set('error', null); codemirror.performLint(); const noErrors = codemirror.state.lint.marked.length === 0; if (noErrors) { - this.get('secretData').fromJSONString(val); + try { + this.get('secretData').fromJSONString(val); + } catch (e) { + this.set('error', e.message); + } } this.set('hasLintError', !noErrors); this.set('codemirrorString', val); diff --git a/ui/app/helpers/mountable-auth-methods.js b/ui/app/helpers/mountable-auth-methods.js index e56d0872e..e24cdbfac 100644 --- a/ui/app/helpers/mountable-auth-methods.js +++ b/ui/app/helpers/mountable-auth-methods.js @@ -1,6 +1,12 @@ import Ember from 'ember'; const MOUNTABLE_AUTH_METHODS = [ + { + displayName: 'AliCloud', + value: 'alicloud', + type: 'alicloud', + category: 'cloud', + }, { displayName: 'AppRole', value: 'approle', @@ -79,7 +85,7 @@ const MOUNTABLE_AUTH_METHODS = [ ]; export function methods() { - return MOUNTABLE_AUTH_METHODS; + return MOUNTABLE_AUTH_METHODS.slice(); } export default Ember.Helper.helper(methods); diff --git a/ui/app/helpers/mountable-secret-engines.js b/ui/app/helpers/mountable-secret-engines.js index 071e6812c..2b5936764 100644 --- a/ui/app/helpers/mountable-secret-engines.js +++ b/ui/app/helpers/mountable-secret-engines.js @@ -13,6 +13,12 @@ const MOUNTABLE_SECRET_ENGINES = [ type: 'aws', category: 'cloud', }, + { + displayName: 'Azure', + value: 'azure', + type: 'azure', + category: 'cloud', + }, { displayName: 'Consul', value: 'consul', @@ -76,7 +82,7 @@ const MOUNTABLE_SECRET_ENGINES = [ ]; export function engines() { - return MOUNTABLE_SECRET_ENGINES; + return MOUNTABLE_SECRET_ENGINES.slice(); } export default Ember.Helper.helper(engines); diff --git a/ui/app/lib/kv-object.js b/ui/app/lib/kv-object.js index 4ca3ed136..4c6ec8a3b 100644 --- a/ui/app/lib/kv-object.js +++ b/ui/app/lib/kv-object.js @@ -1,13 +1,18 @@ import Ember from 'ember'; +const { typeOf, guidFor } = Ember; + export default Ember.ArrayProxy.extend({ fromJSON(json) { - const contents = Object.keys(json || []).map(key => { + if (json && typeOf(json) !== 'object') { + throw new Error('Vault expects data to be formatted as an JSON object.'); + } + let contents = Object.keys(json || []).map(key => { let obj = { name: key, value: json[key], }; - Ember.guidFor(obj); + guidFor(obj); return obj; }); this.setObjects( diff --git a/ui/app/templates/components/wizard-content.hbs b/ui/app/templates/components/wizard-content.hbs index a11f14d8a..d69cb6b75 100644 --- a/ui/app/templates/components/wizard-content.hbs +++ b/ui/app/templates/components/wizard-content.hbs @@ -1,15 +1,17 @@
+ The AliCloud auth method provides an automated mechanism to retrieve a Vault token for AliCloud entities. +
++ The Azure secrets engine dynamically generates Azure service principals and role assignments. Vault roles can be mapped to one or more Azure roles, providing a simple, flexible way to manage the permissions granted to generated service principals. +
+Want a tour? Our helpful guide will introduce you to the Vault Web UI.