-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kubernetes Secrets Engine #17893
Merged
Merged
Kubernetes Secrets Engine #17893
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
da75948
Ember Engine for Kubernetes Secrets Engine (#17881)
zofskeez b879092
Kubernetes route plumbing (#17895)
zofskeez 16f8477
adds kubernetes as mountable and supported secrets engine (#17891)
zofskeez 39e67ff
adds models, adapters and serializers for kubernetes secrets engine (…
zofskeez 0d48342
adds mirage factories and handlers for kubernetes (#17943)
zofskeez 3a8ebf0
Kubernetes Secrets Engine Configuration (#18093)
zofskeez 58e10b6
Merge branch 'main' into ui/kubernetes-secrets-engine
zofskeez 8f5c46f
Merge branch 'main' into ui/kubernetes-secrets-engine
zofskeez 2692eb5
Kubernetes Configuration View (#18147)
zofskeez 489e2e5
Kubernetes Roles List (#18211)
zofskeez 5bd9bfe
VAULT-9863 Kubernetes Overview Page (#18232)
kiannaquach c560b12
Kubernetes Secrets Engine Create/Edit Views (#18271)
zofskeez 4133803
fixes issue with overview route showing 404 page (#18303)
zofskeez 6e7384e
Kubernetes Role Details View (#18294)
zofskeez 0de8307
fixes list link for secrets in an ember engine (#18313)
zofskeez 4e46c2e
Manual Testing: Bug Fixes and Improvements (#18333)
zofskeez aff339e
VAULT-9877 Kubernetes Credential Generate/View Pages (#18270)
kiannaquach 2236321
Merge branch 'main' into ui/kubernetes-secrets-engine
zofskeez eae3361
adds acceptance tests for kubernetes secrets engine roles (#18360)
zofskeez 3bff9f9
VAULT-11862 Kubernetes acceptance tests (#18431)
kiannaquach 1534eb4
VAULT-12127 Refactor breadcrumbs to use breadcrumb component (#18489)
kiannaquach 7c98a71
VAULT-12166 add jsdocs to kubernetes secrets engine pages (#18509)
kiannaquach cc2fd48
Merge branch 'main' into ui/kubernetes-secrets-engine
zofskeez 423132d
fixes incorrect merge conflict resolution
zofskeez 68d0bfe
updates kubernetes check env vars endpoint (#18588)
zofskeez c8edd33
Merge branch 'main' into ui/kubernetes-secrets-engine
zofskeez 12b3505
hides kubernetes ca cert field if not defined in configuration view
zofskeez 128fc57
fixes loading substate handling issue (#18592)
zofskeez 74f2493
adds changelog entry
zofskeez File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:feature | ||
ui: Adds Kubernetes secrets engine | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import ApplicationAdapter from 'vault/adapters/application'; | ||
import { encodePath } from 'vault/utils/path-encoding-helpers'; | ||
|
||
export default class KubernetesConfigAdapter extends ApplicationAdapter { | ||
namespace = 'v1'; | ||
|
||
getURL(backend, path = 'config') { | ||
return `${this.buildURL()}/${encodePath(backend)}/${path}`; | ||
} | ||
urlForUpdateRecord(name, modelName, snapshot) { | ||
return this.getURL(snapshot.attr('backend')); | ||
} | ||
urlForDeleteRecord(backend) { | ||
return this.getURL(backend); | ||
} | ||
|
||
queryRecord(store, type, query) { | ||
const { backend } = query; | ||
return this.ajax(this.getURL(backend), 'GET').then((resp) => { | ||
resp.backend = backend; | ||
return resp; | ||
}); | ||
} | ||
createRecord() { | ||
return this._saveRecord(...arguments); | ||
} | ||
updateRecord() { | ||
return this._saveRecord(...arguments); | ||
} | ||
_saveRecord(store, { modelName }, snapshot) { | ||
const data = store.serializerFor(modelName).serialize(snapshot); | ||
const url = this.getURL(snapshot.attr('backend')); | ||
return this.ajax(url, 'POST', { data }).then(() => data); | ||
} | ||
checkConfigVars(backend) { | ||
return this.ajax(`${this.getURL(backend, 'check')}`, 'GET'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import NamedPathAdapter from 'vault/adapters/named-path'; | ||
import { encodePath } from 'vault/utils/path-encoding-helpers'; | ||
|
||
export default class KubernetesRoleAdapter extends NamedPathAdapter { | ||
getURL(backend, name) { | ||
const base = `${this.buildURL()}/${encodePath(backend)}/roles`; | ||
return name ? `${base}/${name}` : base; | ||
} | ||
urlForQuery({ backend }) { | ||
return this.getURL(backend); | ||
} | ||
urlForUpdateRecord(name, modelName, snapshot) { | ||
return this.getURL(snapshot.attr('backend'), name); | ||
} | ||
urlForDeleteRecord(name, modelName, snapshot) { | ||
return this.getURL(snapshot.attr('backend'), name); | ||
} | ||
|
||
query(store, type, query) { | ||
const { backend } = query; | ||
return this.ajax(this.getURL(backend), 'GET', { data: { list: true } }).then((resp) => { | ||
return resp.data.keys.map((name) => ({ name, backend })); | ||
}); | ||
} | ||
queryRecord(store, type, query) { | ||
const { backend, name } = query; | ||
return this.ajax(this.getURL(backend, name), 'GET').then((resp) => { | ||
resp.data.backend = backend; | ||
resp.data.name = name; | ||
return resp.data; | ||
}); | ||
} | ||
generateCredentials(backend, data) { | ||
const generateCredentialsUrl = `${this.buildURL()}/${encodePath(backend)}/creds/${data.role}`; | ||
|
||
return this.ajax(generateCredentialsUrl, 'POST', { data }).then((response) => { | ||
const { lease_id, lease_duration, data } = response; | ||
|
||
return { | ||
lease_id, | ||
lease_duration, | ||
...data, | ||
}; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import Model, { attr } from '@ember-data/model'; | ||
import { withFormFields } from 'vault/decorators/model-form-fields'; | ||
|
||
@withFormFields(['kubernetesHost', 'serviceAccountJwt', 'kubernetesCaCert']) | ||
export default class KubernetesConfigModel extends Model { | ||
@attr('string') backend; // dynamic path of secret -- set on response from value passed to queryRecord | ||
@attr('string', { | ||
label: 'Kubernetes host', | ||
subText: | ||
'Kubernetes API URL to connect to. Defaults to https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT if those environment variables are set.', | ||
}) | ||
kubernetesHost; | ||
@attr('string', { | ||
label: 'Service account JWT', | ||
subText: | ||
'The JSON web token of the service account used by the secret engine to manage Kubernetes roles. Defaults to the local pod’s JWT if found.', | ||
}) | ||
serviceAccountJwt; | ||
@attr('string', { | ||
label: 'Kubernetes CA Certificate', | ||
subText: | ||
'PEM-encoded CA certificate to use by the secret engine to verify the Kubernetes API server certificate. Defaults to the local pod’s CA if found.', | ||
editType: 'textarea', | ||
}) | ||
kubernetesCaCert; | ||
@attr('boolean', { defaultValue: false }) disableLocalCaJwt; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import Model, { attr } from '@ember-data/model'; | ||
import { withModelValidations } from 'vault/decorators/model-validations'; | ||
import { withFormFields } from 'vault/decorators/model-form-fields'; | ||
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; | ||
import { tracked } from '@glimmer/tracking'; | ||
|
||
const validations = { | ||
name: [{ type: 'presence', message: 'Name is required' }], | ||
}; | ||
const formFieldProps = [ | ||
'name', | ||
'serviceAccountName', | ||
'kubernetesRoleType', | ||
'kubernetesRoleName', | ||
'allowedKubernetesNamespaces', | ||
'tokenMaxTtl', | ||
'tokenDefaultTtl', | ||
'nameTemplate', | ||
]; | ||
|
||
@withModelValidations(validations) | ||
@withFormFields(formFieldProps) | ||
export default class KubernetesRoleModel extends Model { | ||
@attr('string') backend; // dynamic path of secret -- set on response from value passed to queryRecord | ||
@attr('string', { | ||
label: 'Role name', | ||
subText: 'The role’s name in Vault.', | ||
}) | ||
name; | ||
|
||
@attr('string', { | ||
label: 'Service account name', | ||
subText: 'Vault will use the default template when generating service accounts, roles and role bindings.', | ||
}) | ||
serviceAccountName; | ||
|
||
@attr('string', { | ||
label: 'Kubernetes role type', | ||
editType: 'radio', | ||
possibleValues: ['Role', 'ClusterRole'], | ||
}) | ||
kubernetesRoleType; | ||
|
||
@attr('string', { | ||
label: 'Kubernetes role name', | ||
subText: 'Vault will use the default template when generating service accounts, roles and role bindings.', | ||
}) | ||
kubernetesRoleName; | ||
|
||
@attr('string', { | ||
label: 'Service account name', | ||
subText: 'Vault will use the default template when generating service accounts, roles and role bindings.', | ||
}) | ||
serviceAccountName; | ||
|
||
@attr('string', { | ||
label: 'Allowed Kubernetes namespaces', | ||
subText: | ||
'A list of the valid Kubernetes namespaces in which this role can be used for creating service accounts. If set to "*" all namespaces are allowed.', | ||
}) | ||
allowedKubernetesNamespaces; | ||
|
||
@attr({ | ||
label: 'Max Lease TTL', | ||
editType: 'ttl', | ||
}) | ||
tokenMaxTtl; | ||
|
||
@attr({ | ||
label: 'Default Lease TTL', | ||
editType: 'ttl', | ||
}) | ||
tokenDefaultTtl; | ||
|
||
@attr('string', { | ||
label: 'Name template', | ||
editType: 'optionalText', | ||
defaultSubText: | ||
'Vault will use the default template when generating service accounts, roles and role bindings.', | ||
subText: 'Vault will use the default template when generating service accounts, roles and role bindings.', | ||
}) | ||
nameTemplate; | ||
|
||
@attr extraAnnotations; | ||
@attr extraLabels; | ||
|
||
@attr('string') generatedRoleRules; | ||
|
||
@tracked _generationPreference; | ||
get generationPreference() { | ||
// when the user interacts with the radio cards the value will be set to the pseudo prop which takes precedence | ||
if (this._generationPreference) { | ||
return this._generationPreference; | ||
} | ||
// for existing roles, default the value based on which model prop has value -- only one can be set | ||
let pref = null; | ||
if (this.serviceAccountName) { | ||
pref = 'basic'; | ||
} else if (this.kubernetesRoleName) { | ||
pref = 'expanded'; | ||
} else if (this.generatedRoleRules) { | ||
pref = 'full'; | ||
} | ||
return pref; | ||
} | ||
set generationPreference(pref) { | ||
// unset model props specific to filteredFormFields when changing preference | ||
// only one of service_account_name, kubernetes_role_name or generated_role_rules can be set | ||
const props = { | ||
basic: ['kubernetesRoleType', 'kubernetesRoleName', 'generatedRoleRules', 'nameTemplate'], | ||
expanded: ['serviceAccountName', 'generatedRoleRules'], | ||
full: ['serviceAccountName', 'kubernetesRoleName'], | ||
}[pref]; | ||
props.forEach((prop) => (this[prop] = null)); | ||
this._generationPreference = pref; | ||
} | ||
|
||
get filteredFormFields() { | ||
// return different form fields based on generationPreference | ||
const hiddenFieldIndices = { | ||
basic: [2, 3, 7], // kubernetesRoleType, kubernetesRoleName and nameTemplate | ||
expanded: [1], // serviceAccountName | ||
full: [1, 3], // serviceAccountName and kubernetesRoleName | ||
}[this.generationPreference]; | ||
|
||
return hiddenFieldIndices | ||
? this.formFields.filter((field, index) => !hiddenFieldIndices.includes(index)) | ||
: null; | ||
} | ||
|
||
@lazyCapabilities(apiPath`${'backend'}/roles/${'name'}`, 'backend', 'name') rolePath; | ||
@lazyCapabilities(apiPath`${'backend'}/creds/${'name'}`, 'backend', 'name') credsPath; | ||
@lazyCapabilities(apiPath`${'backend'}/roles`, 'backend') rolesPath; | ||
|
||
get canCreate() { | ||
return this.rolePath.get('canCreate'); | ||
} | ||
get canDelete() { | ||
return this.rolePath.get('canDelete'); | ||
} | ||
get canEdit() { | ||
return this.rolePath.get('canUpdate'); | ||
} | ||
get canRead() { | ||
return this.rolePath.get('canRead'); | ||
} | ||
get canList() { | ||
return this.rolesPath.get('canList'); | ||
} | ||
get canGenerateCreds() { | ||
return this.credsPath.get('canCreate'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import ApplicationSerializer from '../application'; | ||
|
||
export default class KubernetesConfigSerializer extends ApplicationSerializer { | ||
primaryKey = 'backend'; | ||
|
||
serialize() { | ||
const json = super.serialize(...arguments); | ||
// remove backend value from payload | ||
delete json.backend; | ||
return json; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import ApplicationSerializer from '../application'; | ||
|
||
export default class KubernetesConfigSerializer extends ApplicationSerializer { | ||
primaryKey = 'name'; | ||
|
||
serialize() { | ||
const json = super.serialize(...arguments); | ||
// remove backend value from payload | ||
delete json.backend; | ||
return json; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zofskeez - Could you please open a PR to change this to the formatting for the "features" section of the changelog? Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mladlow oops I missed that in the readme! Sorry about that. #19062 updates the formatting.