feat(vault): Add CRUDL methods for ssh certificate cred library (#2765)

This defines a new credential library type for ssh certificates.
It adds new repository methods to support CRUDL of the new ssh
certificate credential library.

Co-authored-by: Timothy Messier <tim.messier@gmail.com>
This commit is contained in:
HaotianandTimothy Messier authored and Timothy Messier committed 2023-02-02 17:43:16 +00:00
1 parent 7833dd73c0
commit 823b8cdfc6
14 files changed
+3351 -108

No files matched your search

+1
View File
@@ -30,6 +30,7 @@ const (
UnspecifiedType Type = "unspecified"
UsernamePasswordType Type = "username_password"
SshPrivateKeyType Type = "ssh_private_key"
SshCertificateType Type = "ssh_certificate"
JsonType Type = "json"
)
+12
View File
@@ -9,6 +9,18 @@ const (
httpMethodField = "HttpMethod"
httpRequestBodyField = "HttpRequestBody"
usernameField = "Username"
keyTypeField = "KeyType"
keyBitsField = "KeyBits"
ttlField = "Ttl"
keyIdField = "KeyId"
// CriticalOptionsField represents the field mask indicating a critical option
// update has been requested.
CriticalOptionsField = "CriticalOptions"
// ExtensionsField represents the field mask indicating an extension
// update has been requested.
ExtensionsField = "Extensions"
certificateField = "Certificate"
certificateKeyField = "CertificateKey"
vaultAddressField = "VaultAddress"
+52
View File
@@ -34,6 +34,13 @@ type options struct {
withOverridePrivateKeyAttribute string
withOverridePrivateKeyPassphraseAttribute string
withMappingOverride MappingOverride
withKeyType string
withKeyBits uint32
withTtl string
withKeyId string
withCriticalOptions string
withExtensions string
}
func getDefaultOptions() options {
@@ -174,3 +181,48 @@ func WithMappingOverride(m MappingOverride) Option {
o.withMappingOverride = m
}
}
// WithKeyType provides an optional ssh private key type to use
// with a ssh certificate credential library. Must be rsa, ed25519, or ecdsa.
func WithKeyType(t string) Option {
return func(o *options) {
o.withKeyType = t
}
}
// WithKeyBits provides an optional number of bits used to generate an ssh private key.
func WithKeyBits(b uint32) Option {
return func(o *options) {
o.withKeyBits = b
}
}
// WithTtl provides an optional requested time to live for a generated ssh certificate.
func WithTtl(t string) Option {
return func(o *options) {
o.withTtl = t
}
}
// WithKeyId provides an optional key id for a created certificate.
func WithKeyId(i string) Option {
return func(o *options) {
o.withKeyId = i
}
}
// WithCriticalOptions provides an optional map of the critical options
// that the certificate should be signed for.
func WithCriticalOptions(s string) Option {
return func(o *options) {
o.withCriticalOptions = s
}
}
// WithExtensions provides a optional map of the extensions
// that the certificate should be signed for.
func WithExtensions(s string) Option {
return func(o *options) {
o.withExtensions = s
}
}
+22 -5
View File
@@ -8,18 +8,27 @@ import (
)
func init() {
if err := subtypes.Register(credential.Domain, Subtype, CredentialStorePrefix, CredentialLibraryPrefix, DynamicCredentialPrefix); err != nil {
if err := subtypes.Register(credential.Domain, Subtype, CredentialStorePrefix, DynamicCredentialPrefix); err != nil {
panic(err)
}
if err := subtypes.Register(credential.Domain, GenericLibrarySubtype, CredentialLibraryPrefix); err != nil {
panic(err)
}
if err := subtypes.Register(credential.Domain, SSHCertificateLibrarySubtype, SSHCertificateCredentialLibraryPrefix); err != nil {
panic(err)
}
}
// PublicId prefixes for the resources in the vault package.
const (
CredentialStorePrefix = "csvlt"
CredentialLibraryPrefix = "clvlt"
DynamicCredentialPrefix = "cdvlt"
CredentialStorePrefix = "csvlt"
CredentialLibraryPrefix = "clvlt"
DynamicCredentialPrefix = "cdvlt"
SSHCertificateCredentialLibraryPrefix = "clvsclt"
Subtype = subtypes.Subtype("vault")
Subtype = subtypes.Subtype("vault")
GenericLibrarySubtype = subtypes.Subtype("vault-generic")
SSHCertificateLibrarySubtype = subtypes.Subtype("vault-ssh-certificate")
)
func newCredentialStoreId() (string, error) {
@@ -45,3 +54,11 @@ func newCredentialLibraryId() (string, error) {
}
return id, nil
}
func newSSHCertificateCredentialLibraryId() (string, error) {
id, err := db.NewPublicId(SSHCertificateCredentialLibraryPrefix)
if err != nil {
return "", errors.WrapDeprecated(err, "vault.newSSHCertificateCredentialLibraryPrefix")
}
return id, nil
}
@@ -0,0 +1,363 @@
package vault
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/oplog"
"github.com/hashicorp/go-dbw"
)
// CreateSSHCertificateCredentialLibrary inserts l into the repository and returns a new
// SSHCertificateCredentialLibrary containing the credential library's PublicId. l is not
// changed. l must contain a valid StoreId. l must not contain a PublicId.
// The PublicId is generated and assigned by this method.
//
// Both l.Name and l.Description are optional. If l.Name is set, it must be
// unique within l.StoreId.
//
// Both l.CreateTime and l.UpdateTime are ignored.
func (r *Repository) CreateSSHCertificateCredentialLibrary(ctx context.Context, projectId string, l *SSHCertificateCredentialLibrary, _ ...Option) (*SSHCertificateCredentialLibrary, error) {
const op = "vault.(Repository).CreateSSHCertificateCredentialLibrary"
if l == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "nil SSHCertificateCredentialLibrary")
}
if l.SSHCertificateCredentialLibrary == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "nil embedded l")
}
if l.StoreId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no store id")
}
if l.VaultPath == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no vault path")
}
if l.PublicId != "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "public id not empty")
}
if projectId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no project id")
}
if l.Username == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no username")
}
l = l.clone()
if l.KeyType == "" {
l.KeyType = KeyTypeEd25519
}
if l.KeyBits == KeyBitsDefault {
l.KeyBits = l.getDefaultKeyBits()
}
if l.GetCredentialType() == "" {
l.SSHCertificateCredentialLibrary.CredentialType = string(credential.SshCertificateType)
}
if l.GetCredentialType() != string(credential.SshCertificateType) {
return nil, errors.New(ctx, errors.InvalidParameter, op, "invalid credential type")
}
id, err := newSSHCertificateCredentialLibraryId()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
l.setId(id)
oplogWrapper, err := r.kms.GetWrapper(ctx, projectId, kms.KeyPurposeOplog)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
}
var newSSHCertificateCredentialLibrary *SSHCertificateCredentialLibrary
_, err = r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{},
func(_ db.Reader, w db.Writer) error {
var msgs []*oplog.Message
ticket, err := w.GetTicket(ctx, l)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
}
// insert credential library
newSSHCertificateCredentialLibrary = l.clone()
var lOplogMsg oplog.Message
if err := w.Create(ctx, newSSHCertificateCredentialLibrary, db.NewOplogMsg(&lOplogMsg)); err != nil {
return errors.Wrap(ctx, err, op)
}
msgs = append(msgs, &lOplogMsg)
metadata := l.oplog(oplog.OpType_OP_TYPE_CREATE)
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, ticket, metadata, msgs); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
}
return nil
},
)
if err != nil {
if errors.IsUniqueError(err) {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("in credential store: %s: name %s already exists", l.StoreId, l.Name)))
}
return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("in credential store: %s", l.StoreId)))
}
return newSSHCertificateCredentialLibrary, nil
}
// UpdateSSHCertificateCredentialLibrary updates the repository entry for l.PublicId with
// the values in l for the fields listed in fieldMaskPaths. It returns a
// new SSHCertificateCredentialLibrary containing the updated values and a count of the
// number of records updated. l is not changed.
//
// l must contain a valid PublicId. Name, Description, VaultPath, Username,
// KeyType, KeyBits, Ttl, KeyId, CriticalOptions, and Extensions can be updated. If
// l.Name is set to a non-empty string, it must be unique within l.StoreId.
//
// An attribute of l will be set to NULL in the database if the attribute
// in l is the zero value and it is included in fieldMaskPaths.
func (r *Repository) UpdateSSHCertificateCredentialLibrary(ctx context.Context, projectId string, l *SSHCertificateCredentialLibrary, version uint32, fieldMaskPaths []string, _ ...Option) (*SSHCertificateCredentialLibrary, int, error) {
const op = "vault.(Repository).UpdateSSHCertificateCredentialLibrary"
if l == nil {
return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing SSHCertificateCredentialLibrary")
}
if l.SSHCertificateCredentialLibrary == nil {
return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing embedded SSHCertificateCredentialLibrary")
}
if l.PublicId == "" {
return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidPublicId, op, "missing public id")
}
if version == 0 {
return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing version")
}
if projectId == "" {
return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing project id")
}
l = l.clone()
var keyTypeChange, keyBitChangeDefault bool
for _, f := range fieldMaskPaths {
switch {
case strings.EqualFold(nameField, f):
case strings.EqualFold(descriptionField, f):
case strings.EqualFold(vaultPathField, f):
case strings.EqualFold(usernameField, f):
case strings.EqualFold(keyTypeField, f):
keyTypeChange = true
case strings.EqualFold(keyBitsField, f):
keyBitChangeDefault = l.KeyBits == KeyBitsDefault
case strings.EqualFold(ttlField, f):
case strings.EqualFold(keyIdField, f):
case strings.EqualFold(CriticalOptionsField, f):
case strings.EqualFold(ExtensionsField, f):
default:
return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidFieldMask, op, f)
}
}
if keyTypeChange && l.KeyType == "" {
l.KeyType = KeyTypeEd25519
}
if keyTypeChange && keyBitChangeDefault {
l.KeyBits = l.getDefaultKeyBits()
}
origLib, err := r.LookupSSHCertificateCredentialLibrary(ctx, l.PublicId)
switch {
case err != nil:
return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op)
case origLib == nil:
return nil, db.NoRowsAffected, errors.New(ctx, errors.RecordNotFound, op, fmt.Sprintf("credential library %s", l.PublicId))
}
if keyBitChangeDefault && !keyTypeChange {
l.KeyBits = origLib.getDefaultKeyBits()
}
var dbMask, nullFields []string
dbMask, nullFields = dbw.BuildUpdatePaths(
map[string]any{
nameField: l.Name,
descriptionField: l.Description,
vaultPathField: l.VaultPath,
usernameField: l.Username,
keyTypeField: l.KeyType,
keyBitsField: l.KeyBits,
ttlField: l.Ttl,
keyIdField: l.KeyId,
CriticalOptionsField: l.CriticalOptions,
ExtensionsField: l.Extensions,
},
fieldMaskPaths,
[]string{keyBitsField},
)
if len(dbMask) == 0 && len(nullFields) == 0 {
return nil, db.NoRowsAffected, errors.New(ctx, errors.EmptyFieldMask, op, "missing field mask")
}
oplogWrapper, err := r.kms.GetWrapper(ctx, projectId, kms.KeyPurposeOplog)
if err != nil {
return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithCode(errors.Encrypt),
errors.WithMsg("unable to get oplog wrapper"))
}
var rowsUpdated int
var returnedCredentialLibrary *SSHCertificateCredentialLibrary
_, err = r.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{},
func(rr db.Reader, w db.Writer) error {
var msgs []*oplog.Message
ticket, err := w.GetTicket(ctx, l)
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket"))
}
l := l.clone()
var lOplogMsg oplog.Message
// Update the credential library table
switch {
case len(dbMask) == 0 && len(nullFields) == 0:
// the credential library's fields are not being updated,
// just one of it's child objects, so we just need to
// update the library's version.
l.Version = version + 1
rowsUpdated, err = w.Update(ctx, l, []string{"Version"}, nil, db.NewOplogMsg(&lOplogMsg), db.WithVersion(&version))
if err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to update credential library version"))
}
switch rowsUpdated {
case 1:
case 0:
return nil
default:
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("updated credential library version and %d rows updated", rowsUpdated))
}
default:
rowsUpdated, err = w.Update(ctx, l, dbMask, nullFields, db.NewOplogMsg(&lOplogMsg), db.WithVersion(&version))
if err != nil {
if errors.IsUniqueError(err) {
return errors.New(ctx, errors.NotUnique, op,
fmt.Sprintf("name %s already exists: %s", l.Name, l.PublicId))
}
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to update credential library"))
}
switch rowsUpdated {
case 1:
case 0:
return nil
default:
return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("updated credential library and %d rows updated", rowsUpdated))
}
}
msgs = append(msgs, &lOplogMsg)
metadata := l.oplog(oplog.OpType_OP_TYPE_UPDATE)
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, ticket, metadata, msgs); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to write oplog"))
}
accl := allocSSHCertificateCredentialLibrary()
accl.PublicId = l.PublicId
if err = rr.LookupById(ctx, accl); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to retrieve updated credential library"))
}
returnedCredentialLibrary = accl
return nil
},
)
if err != nil {
if errors.IsUniqueError(err) {
return nil, db.NoRowsAffected, errors.New(ctx, errors.NotUnique, op,
fmt.Sprintf("name %s already exists: %s", l.Name, l.PublicId))
}
return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(l.PublicId))
}
return returnedCredentialLibrary, rowsUpdated, nil
}
// LookupSSHCertificateCredentialLibrary returns the SSHCertificateCredentialLibrary for publicId.
// Returns nil, nil if no SSHCertificateCredentialLibrary is found for publicId.
func (r *Repository) LookupSSHCertificateCredentialLibrary(ctx context.Context, publicId string, _ ...Option) (*SSHCertificateCredentialLibrary, error) {
const op = "vault.(Repository).LookupCredentialLibrary"
if publicId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no public id")
}
l := allocSSHCertificateCredentialLibrary()
l.PublicId = publicId
if err := r.reader.LookupByPublicId(ctx, l); err != nil {
if errors.IsNotFoundError(err) {
return nil, nil
}
return nil, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for: %s", publicId)))
}
return l, nil
}
// ListSSHCertificateCredentialLibraries returns a slice of SSHCertificateCredentialLibraries for the
// storeId. WithLimit is the only option supported.
func (r *Repository) ListSSHCertificateCredentialLibraries(ctx context.Context, storeId string, opt ...Option) ([]*SSHCertificateCredentialLibrary, error) {
const op = "vault.(Repository).ListSSHCertificateCredentialLibraries"
if storeId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no storeId")
}
opts := getOpts(opt...)
limit := r.defaultLimit
if opts.withLimit != 0 {
// non-zero signals an override of the default limit for the repo.
limit = opts.withLimit
}
var libs []*SSHCertificateCredentialLibrary
err := r.reader.SearchWhere(ctx, &libs, "store_id = ?", []any{storeId}, db.WithLimit(limit))
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
return libs, nil
}
// DeleteSSHCertificateCredentialLibrary deletes publicId from the repository and returns
// the number of records deleted.
func (r *Repository) DeleteSSHCertificateCredentialLibrary(ctx context.Context, projectId string, publicId string, _ ...Option) (int, error) {
const op = "vault.(Repository).DeleteSSHCertificateCredentialLibrary"
if publicId == "" {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "no public id")
}
if projectId == "" {
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "no project id")
}
l := allocSSHCertificateCredentialLibrary()
l.PublicId = publicId
oplogWrapper, err := r.kms.GetWrapper(ctx, projectId, kms.KeyPurposeOplog)
if err != nil {
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
}
var rowsDeleted int
_, err = r.writer.DoTx(
ctx, db.StdRetryCnt, db.ExpBackoff{},
func(_ db.Reader, w db.Writer) (err error) {
dl := l.clone()
rowsDeleted, err = w.Delete(ctx, dl, db.WithOplog(oplogWrapper, l.oplog(oplog.OpType_OP_TYPE_DELETE)))
if err == nil && rowsDeleted > 1 {
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 CredentialLibrary would have been deleted")
}
return err
},
)
if err != nil {
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("delete failed for %s", l.PublicId)))
}
return rowsDeleted, nil
}
File diff suppressed because it is too large. Load diff
@@ -74,7 +74,7 @@ func TestSetupSleepyDevEnvironment(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, store)
libClient := credentiallibraries.NewClient(client)
lib, err := libClient.Create(ctx, store.Item.Id, credentiallibraries.WithVaultCredentialLibraryPath(path.Join("database", "creds", "opened")),
lib, err := libClient.Create(ctx, store.Item.Type, store.Item.Id, credentiallibraries.WithVaultCredentialLibraryPath(path.Join("database", "creds", "opened")),
credentiallibraries.WithVaultCredentialLibraryHttpMethod("GET"),
)
require.NoError(t, err)
@@ -0,0 +1,120 @@
package vault
import (
"github.com/hashicorp/boundary/internal/credential"
"github.com/hashicorp/boundary/internal/credential/vault/store"
"github.com/hashicorp/boundary/internal/oplog"
"google.golang.org/protobuf/proto"
)
const (
KeyTypeEcdsa = "ecdsa"
KeyTypeEd25519 = "ed25519"
KeyTypeRsa = "rsa"
KeyBitsDefault = 0
KeyBitsEcdsa256 = 256
KeyBitsEcdsa384 = 384
KeyBitsEcdsa521 = 521
KeyBitsRsa2048 = 2048
KeyBitsRsa3072 = 3072
KeyBitsRsa4096 = 4096
)
// SSHCertificateCredentialLibrary is a credential library that issues
// ssh certificate using the vault ssh secret engine.
// See: https://developer.hashicorp.com/vault/api-docs/secret/ssh#sign-ssh-key
type SSHCertificateCredentialLibrary struct {
*store.SSHCertificateCredentialLibrary
tableName string `gorm:"-"`
}
// NewSSHCertificateCredentialLibrary creates a new in memory SSHCertificateCredentialLibrary
// for a Vault backend at vaultPath assigned to storeId. The SSH username field must be set.
// Name, description, key type, key bits, ttl, key id, critical options, and extensions
// are the only valid options. All other options are ignored.
func NewSSHCertificateCredentialLibrary(storeId string, vaultPath string, username string, opt ...Option) (*SSHCertificateCredentialLibrary, error) {
const op = "vault.NewSSHCertificateCredentialLibrary"
opts := getOpts(opt...)
l := &SSHCertificateCredentialLibrary{
SSHCertificateCredentialLibrary: &store.SSHCertificateCredentialLibrary{
StoreId: storeId,
Name: opts.withName,
Description: opts.withDescription,
VaultPath: vaultPath,
Username: username,
KeyType: opts.withKeyType,
KeyBits: opts.withKeyBits,
Ttl: opts.withTtl,
KeyId: opts.withKeyId,
CriticalOptions: opts.withCriticalOptions,
Extensions: opts.withExtensions,
CredentialType: string(credential.SshCertificateType),
},
}
return l, nil
}
func allocSSHCertificateCredentialLibrary() *SSHCertificateCredentialLibrary {
return &SSHCertificateCredentialLibrary{
SSHCertificateCredentialLibrary: &store.SSHCertificateCredentialLibrary{},
}
}
func (l *SSHCertificateCredentialLibrary) clone() *SSHCertificateCredentialLibrary {
cp := proto.Clone(l.SSHCertificateCredentialLibrary)
return &SSHCertificateCredentialLibrary{
SSHCertificateCredentialLibrary: cp.(*store.SSHCertificateCredentialLibrary),
}
}
func (l *SSHCertificateCredentialLibrary) setId(i string) {
l.PublicId = i
}
// TableName returns the table name.
func (l *SSHCertificateCredentialLibrary) TableName() string {
if l.tableName != "" {
return l.tableName
}
return "credential_vault_ssh_cert_library"
}
// SetTableName sets the table name.
func (l *SSHCertificateCredentialLibrary) SetTableName(n string) {
l.tableName = n
}
func (l *SSHCertificateCredentialLibrary) oplog(op oplog.OpType) oplog.Metadata {
metadata := oplog.Metadata{
"resource-public-id": []string{l.PublicId},
"resource-type": []string{"credential-vault-ssh-cert-library"},
"op-type": []string{op.String()},
}
if l.StoreId != "" {
metadata["store-id"] = []string{l.StoreId}
}
return metadata
}
func (l *SSHCertificateCredentialLibrary) getDefaultKeyBits() uint32 {
switch l.KeyType {
case KeyTypeEcdsa:
return KeyBitsEcdsa256
case KeyTypeRsa:
return KeyBitsRsa2048
default:
return KeyBitsDefault
}
}
// CredentialType returns the type of credential the library retrieves.
func (l *SSHCertificateCredentialLibrary) CredentialType() credential.Type {
return credential.Type(l.SSHCertificateCredentialLibrary.CredentialType)
}
var _ credential.Library = (*SSHCertificateCredentialLibrary)(nil)
+380 -102
View File
@@ -629,6 +629,210 @@ func (x *CredentialLibrary) GetCredentialType() string {
return ""
}
type SSHCertificateCredentialLibrary struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// public_id is a surrogate key suitable for use in a public API.
// @inject_tag: `gorm:"primary_key"`
PublicId string `protobuf:"bytes,1,opt,name=public_id,json=publicId,proto3" json:"public_id,omitempty" gorm:"primary_key"`
// create_time is set by the database.
// @inject_tag: `gorm:"default:current_timestamp"`
CreateTime *timestamp.Timestamp `protobuf:"bytes,2,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
// update_time is set by the database.
// @inject_tag: `gorm:"default:current_timestamp"`
UpdateTime *timestamp.Timestamp `protobuf:"bytes,3,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty" gorm:"default:current_timestamp"`
// name is optional. If set, it must be unique within project_id.
// @inject_tag: `gorm:"default:null"`
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty" gorm:"default:null"`
// description is optional.
// @inject_tag: `gorm:"default:null"`
Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty" gorm:"default:null"`
// store_id of the owning vault credential store.
// It must be set.
// @inject_tag: `gorm:"not_null"`
StoreId string `protobuf:"bytes,6,opt,name=store_id,json=storeId,proto3" json:"store_id,omitempty" gorm:"not_null"`
// version allows optimistic locking of the resource.
// @inject_tag: `gorm:"default:null"`
Version uint32 `protobuf:"varint,7,opt,name=version,proto3" json:"version,omitempty" gorm:"default:null"`
// vault_path is the path in Vault to request credentials from.
// It must be set.
// @inject_tag: `gorm:"not_null"`
VaultPath string `protobuf:"bytes,8,opt,name=vault_path,json=vaultPath,proto3" json:"vault_path,omitempty" gorm:"not_null"`
// username is the username to use when making an SSH connection.
// It must be set.
// @inject_tag: `gorm:"not_null"`
Username string `protobuf:"bytes,9,opt,name=username,proto3" json:"username,omitempty" gorm:"not_null"`
// key_type specifies the key type to use when generating an SSH private key.
// Values must be "rsa", "ed25519", or "ecdsa".
// @inject_tag: `gorm:"not_null"`
KeyType string `protobuf:"bytes,10,opt,name=key_type,json=keyType,proto3" json:"key_type,omitempty" gorm:"not_null"`
// key_bits specifies the number of bits to use to generate an SSH private key.
// Not used if key_type is ed25519.
// @inject_tag: `gorm:"not_null"`
KeyBits uint32 `protobuf:"varint,11,opt,name=key_bits,json=keyBits,proto3" json:"key_bits,omitempty" gorm:"not_null"`
// ttl specifies the requested time to live for the certificate.
// @inject_tag: `gorm:"default:null"`
Ttl string `protobuf:"bytes,12,opt,name=ttl,proto3" json:"ttl,omitempty" gorm:"default:null"`
// key_id specifies the key id that the created certificate should have.
// @inject_tag: `gorm:"default:null"`
KeyId string `protobuf:"bytes,13,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty" gorm:"default:null"`
// critical_options specifies a map of the critical options that the certificate should be signed for.
// @inject_tag: `gorm:"default:null"`
CriticalOptions string `protobuf:"bytes,14,opt,name=critical_options,json=criticalOptions,proto3" json:"critical_options,omitempty" gorm:"default:null"`
// extensions specifies a map of the extensions that the certificate should be signed for.
// @inject_tag: `gorm:"default:null"`
Extensions string `protobuf:"bytes,15,opt,name=extensions,proto3" json:"extensions,omitempty" gorm:"default:null"`
// credential_type is always ssh_certificate
// @inject_tag: `gorm:"default:null"`
CredentialType string `protobuf:"bytes,16,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty" gorm:"default:null"`
}
func (x *SSHCertificateCredentialLibrary) Reset() {
*x = SSHCertificateCredentialLibrary{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SSHCertificateCredentialLibrary) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SSHCertificateCredentialLibrary) ProtoMessage() {}
func (x *SSHCertificateCredentialLibrary) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SSHCertificateCredentialLibrary.ProtoReflect.Descriptor instead.
func (*SSHCertificateCredentialLibrary) Descriptor() ([]byte, []int) {
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{4}
}
func (x *SSHCertificateCredentialLibrary) GetPublicId() string {
if x != nil {
return x.PublicId
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetCreateTime() *timestamp.Timestamp {
if x != nil {
return x.CreateTime
}
return nil
}
func (x *SSHCertificateCredentialLibrary) GetUpdateTime() *timestamp.Timestamp {
if x != nil {
return x.UpdateTime
}
return nil
}
func (x *SSHCertificateCredentialLibrary) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetStoreId() string {
if x != nil {
return x.StoreId
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *SSHCertificateCredentialLibrary) GetVaultPath() string {
if x != nil {
return x.VaultPath
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetKeyType() string {
if x != nil {
return x.KeyType
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetKeyBits() uint32 {
if x != nil {
return x.KeyBits
}
return 0
}
func (x *SSHCertificateCredentialLibrary) GetTtl() string {
if x != nil {
return x.Ttl
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetKeyId() string {
if x != nil {
return x.KeyId
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetCriticalOptions() string {
if x != nil {
return x.CriticalOptions
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetExtensions() string {
if x != nil {
return x.Extensions
}
return ""
}
func (x *SSHCertificateCredentialLibrary) GetCredentialType() string {
if x != nil {
return x.CredentialType
}
return ""
}
type Credential struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -688,7 +892,7 @@ type Credential struct {
func (x *Credential) Reset() {
*x = Credential{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[4]
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -701,7 +905,7 @@ func (x *Credential) String() string {
func (*Credential) ProtoMessage() {}
func (x *Credential) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[4]
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -714,7 +918,7 @@ func (x *Credential) ProtoReflect() protoreflect.Message {
// Deprecated: Use Credential.ProtoReflect.Descriptor instead.
func (*Credential) Descriptor() ([]byte, []int) {
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{4}
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{5}
}
func (x *Credential) GetPublicId() string {
@@ -832,7 +1036,7 @@ type UsernamePasswordOverride struct {
func (x *UsernamePasswordOverride) Reset() {
*x = UsernamePasswordOverride{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[5]
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -845,7 +1049,7 @@ func (x *UsernamePasswordOverride) String() string {
func (*UsernamePasswordOverride) ProtoMessage() {}
func (x *UsernamePasswordOverride) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[5]
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -858,7 +1062,7 @@ func (x *UsernamePasswordOverride) ProtoReflect() protoreflect.Message {
// Deprecated: Use UsernamePasswordOverride.ProtoReflect.Descriptor instead.
func (*UsernamePasswordOverride) Descriptor() ([]byte, []int) {
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{5}
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{6}
}
func (x *UsernamePasswordOverride) GetLibraryId() string {
@@ -923,7 +1127,7 @@ type SshPrivateKeyOverride struct {
func (x *SshPrivateKeyOverride) Reset() {
*x = SshPrivateKeyOverride{}
if protoimpl.UnsafeEnabled {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[6]
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -936,7 +1140,7 @@ func (x *SshPrivateKeyOverride) String() string {
func (*SshPrivateKeyOverride) ProtoMessage() {}
func (x *SshPrivateKeyOverride) ProtoReflect() protoreflect.Message {
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[6]
mi := &file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -949,7 +1153,7 @@ func (x *SshPrivateKeyOverride) ProtoReflect() protoreflect.Message {
// Deprecated: Use SshPrivateKeyOverride.ProtoReflect.Descriptor instead.
func (*SshPrivateKeyOverride) Descriptor() ([]byte, []int) {
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{6}
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP(), []int{7}
}
func (x *SshPrivateKeyOverride) GetLibraryId() string {
@@ -1146,72 +1350,131 @@ var file_controller_storage_credential_vault_store_v1_vault_proto_rawDesc = []by
0x0f, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6f, 0x64, 0x79,
0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x74,
0x79, 0x70, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x22, 0xc3, 0x04, 0x0a, 0x0a, 0x43, 0x72,
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79,
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61,
0x72, 0x79, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x68, 0x6d, 0x61,
0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x48, 0x6d,
0x61, 0x63, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06,
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x22, 0xaa, 0x07, 0x0a, 0x1f, 0x53, 0x53,
0x48, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x1b, 0x0a,
0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76,
0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x54, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42,
0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52,
0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x12, 0x3f, 0x0a, 0x0a, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18,
0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x20, 0xc2, 0xdd, 0x29, 0x1c, 0x0a, 0x09, 0x56, 0x61, 0x75,
0x6c, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x73, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x52, 0x09, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x61,
0x74, 0x68, 0x12, 0x3f, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09,
0x20, 0x01, 0x28, 0x09, 0x42, 0x23, 0xc2, 0xdd, 0x29, 0x1f, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xc2, 0xdd, 0x29, 0x1e, 0x0a, 0x07, 0x4b, 0x65, 0x79,
0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x54, 0x79,
0x70, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x0b,
0x20, 0x01, 0x28, 0x0d, 0x42, 0x22, 0xc2, 0xdd, 0x29, 0x1e, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x42,
0x69, 0x74, 0x73, 0x12, 0x13, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e,
0x6b, 0x65, 0x79, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x42, 0x69, 0x74,
0x73, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x42, 0x19,
0xc2, 0xdd, 0x29, 0x15, 0x0a, 0x03, 0x54, 0x74, 0x6c, 0x12, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x74, 0x74, 0x6c, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x35,
0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e,
0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x05, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x11, 0x61, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x05,
0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x5d, 0x0a, 0x10, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
0x6c, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x42,
0x32, 0xc2, 0xdd, 0x29, 0x2e, 0x0a, 0x0f, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x4f,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x73, 0x2e, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6f, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x52, 0x0f, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x4f, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x12, 0x47, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xc2, 0xdd, 0x29, 0x23, 0x0a, 0x0a,
0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x15, 0x61, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x73, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x27, 0x0a,
0x0f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65,
0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x22, 0xc3, 0x04, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49,
0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64,
0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x68, 0x6d, 0x61, 0x63, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x48, 0x6d, 0x61, 0x63, 0x12,
0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f,
0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f,
0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x53, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x6e, 0x65, 0x77,
0x61, 0x62, 0x6c, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x52, 0x65,
0x6e, 0x65, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22,
0x97, 0x01, 0x0a, 0x18, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x75,
0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x22, 0xe2, 0x01, 0x0a, 0x15, 0x53, 0x73,
0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x4f, 0x76, 0x65, 0x72, 0x72,
0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79,
0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61,
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11,
0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79,
0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x13, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f,
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x1d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70,
0x68, 0x72, 0x61, 0x73, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x42, 0x45,
0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x61, 0x6c, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f,
0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x6e,
0x65, 0x77, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76,
0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x6c, 0x61, 0x73,
0x74, 0x52, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x53, 0x0a, 0x0f,
0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d,
0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x62, 0x6c,
0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x52, 0x65, 0x6e, 0x65, 0x77,
0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x97, 0x01, 0x0a,
0x18, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x62,
0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c,
0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72,
0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x41, 0x74,
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x70, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x41, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x22, 0xe2, 0x01, 0x0a, 0x15, 0x53, 0x73, 0x68, 0x50, 0x72,
0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x49, 0x64, 0x12,
0x2d, 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65,
0x72, 0x6e, 0x61, 0x6d, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x32,
0x0a, 0x15, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x74,
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70,
0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
0x74, 0x65, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65,
0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x70, 0x72,
0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61,
0x73, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x42, 0x45, 0x5a, 0x43, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f,
0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1226,36 +1489,39 @@ func file_controller_storage_credential_vault_store_v1_vault_proto_rawDescGZIP()
return file_controller_storage_credential_vault_store_v1_vault_proto_rawDescData
}
var file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_controller_storage_credential_vault_store_v1_vault_proto_goTypes = []interface{}{
(*CredentialStore)(nil), // 0: controller.storage.credential.vault.store.v1.CredentialStore
(*Token)(nil), // 1: controller.storage.credential.vault.store.v1.Token
(*ClientCertificate)(nil), // 2: controller.storage.credential.vault.store.v1.ClientCertificate
(*CredentialLibrary)(nil), // 3: controller.storage.credential.vault.store.v1.CredentialLibrary
(*Credential)(nil), // 4: controller.storage.credential.vault.store.v1.Credential
(*UsernamePasswordOverride)(nil), // 5: controller.storage.credential.vault.store.v1.UsernamePasswordOverride
(*SshPrivateKeyOverride)(nil), // 6: controller.storage.credential.vault.store.v1.SshPrivateKeyOverride
(*timestamp.Timestamp)(nil), // 7: controller.storage.timestamp.v1.Timestamp
(*CredentialStore)(nil), // 0: controller.storage.credential.vault.store.v1.CredentialStore
(*Token)(nil), // 1: controller.storage.credential.vault.store.v1.Token
(*ClientCertificate)(nil), // 2: controller.storage.credential.vault.store.v1.ClientCertificate
(*CredentialLibrary)(nil), // 3: controller.storage.credential.vault.store.v1.CredentialLibrary
(*SSHCertificateCredentialLibrary)(nil), // 4: controller.storage.credential.vault.store.v1.SSHCertificateCredentialLibrary
(*Credential)(nil), // 5: controller.storage.credential.vault.store.v1.Credential
(*UsernamePasswordOverride)(nil), // 6: controller.storage.credential.vault.store.v1.UsernamePasswordOverride
(*SshPrivateKeyOverride)(nil), // 7: controller.storage.credential.vault.store.v1.SshPrivateKeyOverride
(*timestamp.Timestamp)(nil), // 8: controller.storage.timestamp.v1.Timestamp
}
var file_controller_storage_credential_vault_store_v1_vault_proto_depIdxs = []int32{
7, // 0: controller.storage.credential.vault.store.v1.CredentialStore.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 1: controller.storage.credential.vault.store.v1.CredentialStore.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 2: controller.storage.credential.vault.store.v1.CredentialStore.delete_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 3: controller.storage.credential.vault.store.v1.Token.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 4: controller.storage.credential.vault.store.v1.Token.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 5: controller.storage.credential.vault.store.v1.Token.last_renewal_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 6: controller.storage.credential.vault.store.v1.Token.expiration_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 7: controller.storage.credential.vault.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 8: controller.storage.credential.vault.store.v1.CredentialLibrary.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 9: controller.storage.credential.vault.store.v1.Credential.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 10: controller.storage.credential.vault.store.v1.Credential.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 11: controller.storage.credential.vault.store.v1.Credential.last_renewal_time:type_name -> controller.storage.timestamp.v1.Timestamp
7, // 12: controller.storage.credential.vault.store.v1.Credential.expiration_time:type_name -> controller.storage.timestamp.v1.Timestamp
13, // [13:13] is the sub-list for method output_type
13, // [13:13] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension type_name
13, // [13:13] is the sub-list for extension extendee
0, // [0:13] is the sub-list for field type_name
8, // 0: controller.storage.credential.vault.store.v1.CredentialStore.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 1: controller.storage.credential.vault.store.v1.CredentialStore.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 2: controller.storage.credential.vault.store.v1.CredentialStore.delete_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 3: controller.storage.credential.vault.store.v1.Token.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 4: controller.storage.credential.vault.store.v1.Token.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 5: controller.storage.credential.vault.store.v1.Token.last_renewal_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 6: controller.storage.credential.vault.store.v1.Token.expiration_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 7: controller.storage.credential.vault.store.v1.CredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 8: controller.storage.credential.vault.store.v1.CredentialLibrary.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 9: controller.storage.credential.vault.store.v1.SSHCertificateCredentialLibrary.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 10: controller.storage.credential.vault.store.v1.SSHCertificateCredentialLibrary.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 11: controller.storage.credential.vault.store.v1.Credential.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 12: controller.storage.credential.vault.store.v1.Credential.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 13: controller.storage.credential.vault.store.v1.Credential.last_renewal_time:type_name -> controller.storage.timestamp.v1.Timestamp
8, // 14: controller.storage.credential.vault.store.v1.Credential.expiration_time:type_name -> controller.storage.timestamp.v1.Timestamp
15, // [15:15] is the sub-list for method output_type
15, // [15:15] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
}
func init() { file_controller_storage_credential_vault_store_v1_vault_proto_init() }
@@ -1313,7 +1579,7 @@ func file_controller_storage_credential_vault_store_v1_vault_proto_init() {
}
}
file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Credential); i {
switch v := v.(*SSHCertificateCredentialLibrary); i {
case 0:
return &v.state
case 1:
@@ -1325,7 +1591,7 @@ func file_controller_storage_credential_vault_store_v1_vault_proto_init() {
}
}
file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UsernamePasswordOverride); i {
switch v := v.(*Credential); i {
case 0:
return &v.state
case 1:
@@ -1337,6 +1603,18 @@ func file_controller_storage_credential_vault_store_v1_vault_proto_init() {
}
}
file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UsernamePasswordOverride); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_controller_storage_credential_vault_store_v1_vault_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SshPrivateKeyOverride); i {
case 0:
return &v.state
@@ -1355,7 +1633,7 @@ func file_controller_storage_credential_vault_store_v1_vault_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_controller_storage_credential_vault_store_v1_vault_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumMessages: 8,
NumExtensions: 0,
NumServices: 0,
},
+32
View File
@@ -140,6 +140,38 @@ func TestCredentialLibraries(t testing.TB, conn *db.DB, _ wrapping.Wrapper, stor
return libs
}
// TestSSHCertificateCredentialLibraries creates count number of vault credential
// libraries in the provided DB with the provided store id. If any errors
// are encountered during the creation of the credential libraries, the
// test will fail.
func TestSSHCertificateCredentialLibraries(t testing.TB, conn *db.DB, _ wrapping.Wrapper, storeId string, count int) []*SSHCertificateCredentialLibrary {
t.Helper()
assert, require := assert.New(t), require.New(t)
w := db.New(conn)
var libs []*SSHCertificateCredentialLibrary
for i := 0; i < count; i++ {
lib, err := NewSSHCertificateCredentialLibrary(storeId, fmt.Sprintf("vault/path%d", i), "username", withKeyType(KeyTypeEd25519))
assert.NoError(err)
require.NotNil(lib)
id, err := newSSHCertificateCredentialLibraryId()
assert.NoError(err)
require.NotEmpty(id)
lib.PublicId = id
ctx := context.Background()
_, err2 := w.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{},
func(_ db.Reader, iw db.Writer) error {
return iw.Create(ctx, lib)
},
)
require.NoError(err2)
libs = append(libs, lib)
}
return libs
}
// TestCredentials creates count number of vault credentials in the provided DB with
// the provided library id and session id. If any errors are encountered
// during the creation of the credentials, the test will fail.
@@ -6,6 +6,7 @@ begin;
-- Add new constraint that only allows known types
-- This replaces the constraint defined in 36/01_credential_type_up
-- Replaced in 63/01_credential_vault_ssh_cert_library
alter table credential_type_enm
add constraint only_predefined_credential_types_allowed
check (
@@ -0,0 +1,170 @@
begin;
-- drop constraint so we can add ssh_certificate
alter table credential_type_enm
drop constraint only_predefined_credential_types_allowed;
-- Add new constraint that only allows known types
-- This replaces the constraint defined in 39/01_static_ssh_private_key_creds_up
alter table credential_type_enm
add constraint only_predefined_credential_types_allowed
check (
name in (
'unspecified',
'username_password',
'ssh_private_key',
'ssh_certificate'
)
);
insert into credential_type_enm (name)
values ('ssh_certificate');
create table credential_vault_ssh_cert_key_type_enm (
name text primary key
constraint only_predefined_key_types_allowed
check (
name in (
'ed25519',
'ecdsa',
'rsa'
)
)
);
comment on table credential_vault_ssh_cert_key_type_enm is
'credential_vault_ssh_cert_key_type_enm is an enumeration table for the ssh key type. ';
insert into credential_vault_ssh_cert_key_type_enm (name)
values
('ed25519'),
('ecdsa'),
('rsa');
create table credential_vault_ssh_cert_key_bits_enm (
bits int primary key
constraint only_predefined_key_bits_allowed
check (
bits in (
0,
2048,
3072,
4096,
256,
384,
521
)
)
);
comment on table credential_vault_ssh_cert_key_bits_enm is
'credential_vault_ssh_cert_key_bits_enm is an enumeration table for the ssh key bits. ';
insert into credential_vault_ssh_cert_key_bits_enm (bits)
values
(0),
(2048),
(3072),
(4096),
(256),
(384),
(521);
create table credential_vault_ssh_cert_valid_key_type_key_bits (
key_type text not null
constraint credential_vault_ssh_cert_key_type_enm_fkey
references credential_vault_ssh_cert_key_type_enm (name),
key_bits int not null
constraint credential_vault_ssh_cert_key_bits_enm_fkey
references credential_vault_ssh_cert_key_bits_enm (bits),
constraint credential_vault_ssh_cert_valid_key_type_key_bits_uq
unique(key_type, key_bits)
);
insert into credential_vault_ssh_cert_valid_key_type_key_bits (key_type, key_bits)
values
('ed25519', 0),
('ecdsa', 256),
('ecdsa', 384),
('ecdsa', 521),
('rsa', 2048),
('rsa', 3072),
('rsa', 4096);
create table credential_vault_ssh_cert_library (
public_id wt_public_id primary key,
store_id wt_public_id not null
constraint credential_vault_store_fkey
references credential_vault_store (public_id)
on delete cascade
on update cascade,
name wt_name,
description wt_description,
create_time wt_timestamp,
update_time wt_timestamp,
version wt_version,
vault_path text not null
constraint vault_path_must_not_be_empty
check(length(trim(vault_path)) > 0)
constraint vault_path_must_be_sign_or_issue
check(vault_path ~ '^.+\/(sign|issue)\/[^\/\\\s]+$'),
username text not null
constraint username_must_not_be_empty
check(length(trim(username)) > 0),
key_type text not null,
key_bits int not null,
ttl text,
key_id text,
critical_options bytea,
extensions bytea,
credential_type text,
project_id wt_public_id not null,
constraint credential_vault_ssh_cert_library_store_id_name_uq
unique(store_id, name),
constraint credential_vault_ssh_cert_library_store_id_public_id_uq
unique(store_id, public_id),
constraint credential_library_fkey
foreign key (project_id, store_id, public_id, credential_type)
references credential_library (project_id, store_id, public_id, credential_type)
on delete cascade
on update cascade,
constraint credential_vault_ssh_cert_valid_key_type_key_bits_fkey
foreign key (key_type, key_bits)
references credential_vault_ssh_cert_valid_key_type_key_bits(key_type, key_bits)
);
comment on table credential_vault_ssh_cert_library is
'credential_vault_ssh_cert_library a credential library that issues credentials from a vault ssh secret backend.';
create function default_ssh_certificate_credential_type() returns trigger
as $$
begin
if new.credential_type is distinct from 'ssh_certificate' then
raise warning 'credential_vault_ssh_cert_library only supports ssh_certificate credentials';
new.credential_type = 'ssh_certificate';
end if;
return new;
end;
$$ language plpgsql;
comment on function default_ssh_certificate_credential_type is
'default_ssh_certificate_credential_type ensures the credential_type is set to ssh_certificate';
create trigger default_ssh_certificate_credential_type before insert on credential_vault_ssh_cert_library
for each row execute procedure default_ssh_certificate_credential_type();
create trigger insert_credential_library_subtype before insert on credential_vault_ssh_cert_library
for each row execute procedure insert_credential_library_subtype();
create trigger default_create_time_column before insert on credential_vault_ssh_cert_library
for each row execute procedure default_create_time();
create trigger delete_credential_library_subtype after delete on credential_vault_ssh_cert_library
for each row execute procedure delete_credential_library_subtype();
create trigger immutable_columns before update on credential_vault_ssh_cert_library
for each row execute procedure immutable_columns('public_id', 'store_id', 'project_id', 'credential_type', 'create_time');
create trigger update_time_column before update on credential_vault_ssh_cert_library
for each row execute procedure update_time_column();
create trigger update_version_column after update on credential_vault_ssh_cert_library
for each row execute procedure update_version_column();
create trigger before_insert_credential_vault_library before insert on credential_vault_ssh_cert_library
for each row execute procedure before_insert_credential_vault_library();
insert into oplog_ticket (name, version)
values
('credential_vault_ssh_cert_library', 1);
commit;
@@ -0,0 +1,148 @@
begin;
select plan(16);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets', 'credentials');
-- validate default values
prepare insert_valid as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc1', '/ssh/sign/foo', 'bar', 'ed25519', 0),
('vs_______wvs', 'vl______vsc2', '/ssh/sign/foo', 'bar', 'ecdsa', 256),
('vs_______wvs', 'vl______vsc3', '/ssh/sign/foo', 'bar', 'ecdsa', 384),
('vs_______wvs', 'vl______vsc4', '/ssh/sign/foo', 'bar', 'ecdsa', 521),
('vs_______wvs', 'vl______vsc5', '/ssh/sign/foo', 'bar', 'rsa', 2048),
('vs_______wvs', 'vl______vsc6', '/ssh/sign/foo', 'bar', 'rsa', 3072),
('vs_______wvs', 'vl______vsc7', '/ssh/sign/foo', 'bar', 'rsa', 4096);
prepare select_vault_ssh_cert_libraries as
select public_id::text, store_id::text, name::text, description::text, vault_path, username, key_type, key_bits, ttl, key_id, critical_options, extensions, credential_type, project_id::text
from credential_vault_ssh_cert_library
where public_id like 'vl______vsc%'
order by public_id;
prepare select_libraries as
select public_id::text, store_id::text, credential_type, project_id::text
from credential_library
where public_id in ('vl______vsc1', 'vl______vsc3')
order by public_id;
select lives_ok('insert_valid');
select results_eq(
'select_vault_ssh_cert_libraries',
$$VALUES
('vl______vsc1', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ed25519', 0, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc2', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 256, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc3', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 384, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc4', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 521, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc5', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 2048, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc6', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 3072, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc7', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 4096, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget')$$
);
prepare insert_invalid_key_type as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', 'bar', 'unknown', 256);
select throws_ok('insert_invalid_key_type', 'insert or update on table "credential_vault_ssh_cert_library" violates foreign key constraint "credential_vault_ssh_cert_valid_key_type_key_bits_fkey"');
prepare insert_invalid_key_bits as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', 'bar', 'rsa', 99);
select throws_ok('insert_invalid_key_bits', 'insert or update on table "credential_vault_ssh_cert_library" violates foreign key constraint "credential_vault_ssh_cert_valid_key_type_key_bits_fkey"');
prepare insert_invalid_rsa_key_type_bits_combo as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', 'bar', 'rsa', 384);
select throws_ok('insert_invalid_rsa_key_type_bits_combo', 'insert or update on table "credential_vault_ssh_cert_library" violates foreign key constraint "credential_vault_ssh_cert_valid_key_type_key_bits_fkey"');
prepare insert_invalid_ecdsa_key_type_bits_combo as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', 'bar', 'ecdsa', 2048);
select throws_ok('insert_invalid_ecdsa_key_type_bits_combo', 'insert or update on table "credential_vault_ssh_cert_library" violates foreign key constraint "credential_vault_ssh_cert_valid_key_type_key_bits_fkey"');
prepare insert_invalid_ed25519_key_type_bits_combo as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', 'bar', 'ed25519', 2048);
select throws_ok('insert_invalid_ed25519_key_type_bits_combo', 'insert or update on table "credential_vault_ssh_cert_library" violates foreign key constraint "credential_vault_ssh_cert_valid_key_type_key_bits_fkey"');
prepare insert_invalid_vault_path as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/not-sign/foo', 'bar', 'ed25519', 0);
select throws_ok('insert_invalid_vault_path', 'new row for relation "credential_vault_ssh_cert_library" violates check constraint "vault_path_must_be_sign_or_issue"');
prepare insert_invalid_vault_path_empty as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '', 'bar', 'ed25519', 0);
select throws_ok('insert_invalid_vault_path', 'new row for relation "credential_vault_ssh_cert_library" violates check constraint "vault_path_must_be_sign_or_issue"');
prepare insert_invalid_username as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', '', 'ed25519', 0);
select throws_ok('insert_invalid_username', 'new row for relation "credential_vault_ssh_cert_library" violates check constraint "username_must_not_be_empty"');
prepare insert_invalid_credential_type as
insert into credential_vault_ssh_cert_library
(store_id, public_id, vault_path, username, credential_type, key_type, key_bits)
values
('vs_______wvs', 'vl______vsc8', '/ssh/sign/foo', 'bar', 'username_password', 'ed25519', 0);
select lives_ok('insert_invalid_credential_type');
select results_eq(
'select_vault_ssh_cert_libraries',
$$VALUES
('vl______vsc1', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ed25519', 0, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc2', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 256, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc3', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 384, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc4', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 521, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc5', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 2048, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc6', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 3072, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc7', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 4096, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc8', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ed25519', 0, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget')$$
);
select results_eq(
'select_libraries',
$$VALUES
('vl______vsc1', 'vs_______wvs', 'ssh_certificate', 'p____bwidget'),
('vl______vsc3', 'vs_______wvs', 'ssh_certificate', 'p____bwidget')$$
);
prepare delete_ssh_cred_library as
delete from credential_vault_ssh_cert_library where public_id = 'vl______vsc3';
select lives_ok('delete_ssh_cred_library');
select results_eq(
'select_vault_ssh_cert_libraries',
$$VALUES
('vl______vsc1', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ed25519', 0, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc2', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 256, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc4', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ecdsa', 521, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc5', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 2048, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc6', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 3072, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc7', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'rsa', 4096, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget'),
('vl______vsc8', 'vs_______wvs', null, null, '/ssh/sign/foo', 'bar', 'ed25519', 0, null, null, null::bytea, null::bytea, 'ssh_certificate', 'p____bwidget')$$
);
select results_eq(
'select_libraries',
$$VALUES
('vl______vsc1', 'vs_______wvs', 'ssh_certificate', 'p____bwidget')$$
);
rollback;
@@ -265,6 +265,107 @@ message CredentialLibrary {
string credential_type = 11;
}
message SSHCertificateCredentialLibrary {
// public_id is a surrogate key suitable for use in a public API.
// @inject_tag: `gorm:"primary_key"`
string public_id = 1;
// create_time is set by the database.
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp create_time = 2;
// update_time is set by the database.
// @inject_tag: `gorm:"default:current_timestamp"`
timestamp.v1.Timestamp update_time = 3;
// name is optional. If set, it must be unique within project_id.
// @inject_tag: `gorm:"default:null"`
string name = 4 [(custom_options.v1.mask_mapping) = {
this: "Name"
that: "name"
}];
// description is optional.
// @inject_tag: `gorm:"default:null"`
string description = 5 [(custom_options.v1.mask_mapping) = {
this: "Description"
that: "description"
}];
// store_id of the owning vault credential store.
// It must be set.
// @inject_tag: `gorm:"not_null"`
string store_id = 6;
// version allows optimistic locking of the resource.
// @inject_tag: `gorm:"default:null"`
uint32 version = 7;
// vault_path is the path in Vault to request credentials from.
// It must be set.
// @inject_tag: `gorm:"not_null"`
string vault_path = 8 [(custom_options.v1.mask_mapping) = {
this: "VaultPath"
that: "attributes.path"
}];
// username is the username to use when making an SSH connection.
// It must be set.
// @inject_tag: `gorm:"not_null"`
string username = 9 [(custom_options.v1.mask_mapping) = {
this: "Username"
that: "attributes.username"
}];
// key_type specifies the key type to use when generating an SSH private key.
// Values must be "rsa", "ed25519", or "ecdsa".
// @inject_tag: `gorm:"not_null"`
string key_type = 10 [(custom_options.v1.mask_mapping) = {
this: "KeyType"
that: "attributes.key_type"
}];
// key_bits specifies the number of bits to use to generate an SSH private key.
// Not used if key_type is ed25519.
// @inject_tag: `gorm:"not_null"`
uint32 key_bits = 11 [(custom_options.v1.mask_mapping) = {
this: "KeyBits"
that: "attributes.key_bits"
}];
// ttl specifies the requested time to live for the certificate.
// @inject_tag: `gorm:"default:null"`
string ttl = 12 [(custom_options.v1.mask_mapping) = {
this: "Ttl"
that: "attributes.ttl"
}];
// key_id specifies the key id that the created certificate should have.
// @inject_tag: `gorm:"default:null"`
string key_id = 13 [(custom_options.v1.mask_mapping) = {
this: "KeyId"
that: "attributes.key_id"
}];
// critical_options specifies a map of the critical options that the certificate should be signed for.
// @inject_tag: `gorm:"default:null"`
string critical_options = 14 [(custom_options.v1.mask_mapping) = {
this: "CriticalOptions"
that: "attributes.critical_options"
}];
// extensions specifies a map of the extensions that the certificate should be signed for.
// @inject_tag: `gorm:"default:null"`
string extensions = 15 [(custom_options.v1.mask_mapping) = {
this: "Extensions"
that: "attributes.extensions"
}];
// credential_type is always ssh_certificate
// @inject_tag: `gorm:"default:null"`
string credential_type = 16;
}
message Credential {
// public_id is a surrogate key suitable for use in a public API.
// @inject_tag: `gorm:"primary_key"`