diff --git a/Makefile b/Makefile index efdc02c..cbd24dc 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,12 @@ info: clean: info @ rm -rf target -.PHONY: deps -deps: info clean +.PHONY: dependencies +dependencies: info clean @ go mod tidy .PHONY: test -test: info clean deps +test: info clean dependencies @ go test -v -cover -short $$(go list ./... | grep -v /examples) .PHONY: build @@ -32,26 +32,6 @@ build: info clean @ GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BIN)/darwin/$(SERVICE) cmd/server/main.go @ GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BIN)/linux/$(SERVICE) cmd/server/main.go -.PHONY: postgres -postgres: - @ docker run --name baseca -p 5432:5432 -v /path/to/baseca/db/init:/db/init -e POSTGRES_USER=root -e POSTGRES_PASSWORD=secret -d postgres:latest - -.PHONY: createdb -createdb: - @ docker exec -it baseca createdb --username=root --owner=root baseca - -.PHONY: dropdb -dropdb: - @ docker exec -it baseca dropdb baseca - -.PHONY: migrateup -migrateup: - @ migrate -path db/migration -database "postgresql://root:secret@localhost:5432/baseca?sslmode=disable" -verbose up - -.PHONY: migratedown -migratedown: - @ migrate -path db/migration -database "postgresql://root:secret@localhost:5432/baseca?sslmode=disable" -verbose down - .PHONY: sqlc sqlc: @ sqlc generate -f db/sqlc.yaml @@ -66,7 +46,7 @@ gen: info clean .PHONY: server server: - @ password=${DATABASE_CREDENTIALS} \ + @ database_credentials=${DATABASE_CREDENTIALS} \ go run cmd/server/main.go .PHONY: lint diff --git a/db/migration/000001_init_schema.up.sql b/db/migration/000001_init_schema.up.sql index c7190f4..fa86766 100644 --- a/db/migration/000001_init_schema.up.sql +++ b/db/migration/000001_init_schema.up.sql @@ -22,6 +22,7 @@ CREATE TABLE "accounts" ( "extended_key" varchar(100) NOT NULL, "certificate_validity" smallserial NOT NULL, "subordinate_ca" varchar(100) NOT NULL, + "provisioned" boolean NOT NULL, "node_attestation" varchar(100)[], "created_at" timestamptz NOT NULL DEFAULT (now()), "created_by" uuid NOT NULL diff --git a/db/mock/store.go b/db/mock/store.go index 116854b..4cba965 100644 --- a/db/mock/store.go +++ b/db/mock/store.go @@ -37,6 +37,21 @@ func (m *MockStore) EXPECT() *MockStoreMockRecorder { return m.recorder } +// CreateProvisionerAccount mocks base method. +func (m *MockStore) CreateProvisionerAccount(arg0 context.Context, arg1 db.CreateProvisionerAccountParams) (*db.Provisioner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateProvisionerAccount", arg0, arg1) + ret0, _ := ret[0].(*db.Provisioner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateProvisionerAccount indicates an expected call of CreateProvisionerAccount. +func (mr *MockStoreMockRecorder) CreateProvisionerAccount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProvisionerAccount", reflect.TypeOf((*MockStore)(nil).CreateProvisionerAccount), arg0, arg1) +} + // CreateServiceAccount mocks base method. func (m *MockStore) CreateServiceAccount(arg0 context.Context, arg1 db.CreateServiceAccountParams) (*db.Account, error) { m.ctrl.T.Helper() @@ -81,6 +96,20 @@ func (mr *MockStoreMockRecorder) DeleteInstanceIdentityDocument(arg0, arg1 inter return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteInstanceIdentityDocument", reflect.TypeOf((*MockStore)(nil).DeleteInstanceIdentityDocument), arg0, arg1) } +// DeleteProvisionerAccount mocks base method. +func (m *MockStore) DeleteProvisionerAccount(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteProvisionerAccount", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteProvisionerAccount indicates an expected call of DeleteProvisionerAccount. +func (mr *MockStoreMockRecorder) DeleteProvisionerAccount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProvisionerAccount", reflect.TypeOf((*MockStore)(nil).DeleteProvisionerAccount), arg0, arg1) +} + // DeleteServiceAccount mocks base method. func (m *MockStore) DeleteServiceAccount(arg0 context.Context, arg1 uuid.UUID) error { m.ctrl.T.Helper() @@ -139,6 +168,51 @@ func (mr *MockStoreMockRecorder) GetInstanceIdentityDocument(arg0, arg1 interfac return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceIdentityDocument", reflect.TypeOf((*MockStore)(nil).GetInstanceIdentityDocument), arg0, arg1) } +// GetProvisionerUUID mocks base method. +func (m *MockStore) GetProvisionerUUID(arg0 context.Context, arg1 uuid.UUID) (*db.Provisioner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProvisionerUUID", arg0, arg1) + ret0, _ := ret[0].(*db.Provisioner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProvisionerUUID indicates an expected call of GetProvisionerUUID. +func (mr *MockStoreMockRecorder) GetProvisionerUUID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerUUID", reflect.TypeOf((*MockStore)(nil).GetProvisionerUUID), arg0, arg1) +} + +// GetServiceAccountByMetadata mocks base method. +func (m *MockStore) GetServiceAccountByMetadata(arg0 context.Context, arg1 db.GetServiceAccountByMetadataParams) ([]*db.Account, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceAccountByMetadata", arg0, arg1) + ret0, _ := ret[0].([]*db.Account) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceAccountByMetadata indicates an expected call of GetServiceAccountByMetadata. +func (mr *MockStoreMockRecorder) GetServiceAccountByMetadata(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceAccountByMetadata", reflect.TypeOf((*MockStore)(nil).GetServiceAccountByMetadata), arg0, arg1) +} + +// GetServiceAccountBySAN mocks base method. +func (m *MockStore) GetServiceAccountBySAN(arg0 context.Context, arg1 []string) ([]*db.Account, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceAccountBySAN", arg0, arg1) + ret0, _ := ret[0].([]*db.Account) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceAccountBySAN indicates an expected call of GetServiceAccountBySAN. +func (mr *MockStoreMockRecorder) GetServiceAccountBySAN(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceAccountBySAN", reflect.TypeOf((*MockStore)(nil).GetServiceAccountBySAN), arg0, arg1) +} + // GetServiceAccounts mocks base method. func (m *MockStore) GetServiceAccounts(arg0 context.Context, arg1 string) ([]*db.Account, error) { m.ctrl.T.Helper() @@ -169,6 +243,21 @@ func (mr *MockStoreMockRecorder) GetServiceUUID(arg0, arg1 interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceUUID", reflect.TypeOf((*MockStore)(nil).GetServiceUUID), arg0, arg1) } +// GetSignedCertificateByMetadata mocks base method. +func (m *MockStore) GetSignedCertificateByMetadata(arg0 context.Context, arg1 db.GetSignedCertificateByMetadataParams) ([]*db.Certificate, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSignedCertificateByMetadata", arg0, arg1) + ret0, _ := ret[0].([]*db.Certificate) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSignedCertificateByMetadata indicates an expected call of GetSignedCertificateByMetadata. +func (mr *MockStoreMockRecorder) GetSignedCertificateByMetadata(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignedCertificateByMetadata", reflect.TypeOf((*MockStore)(nil).GetSignedCertificateByMetadata), arg0, arg1) +} + // GetUser mocks base method. func (m *MockStore) GetUser(arg0 context.Context, arg1 string) (*db.User, error) { m.ctrl.T.Helper() @@ -214,6 +303,21 @@ func (mr *MockStoreMockRecorder) ListCertificates(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCertificates", reflect.TypeOf((*MockStore)(nil).ListCertificates), arg0, arg1) } +// ListProvisionerAccounts mocks base method. +func (m *MockStore) ListProvisionerAccounts(arg0 context.Context, arg1 db.ListProvisionerAccountsParams) ([]*db.Provisioner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListProvisionerAccounts", arg0, arg1) + ret0, _ := ret[0].([]*db.Provisioner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListProvisionerAccounts indicates an expected call of ListProvisionerAccounts. +func (mr *MockStoreMockRecorder) ListProvisionerAccounts(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListProvisionerAccounts", reflect.TypeOf((*MockStore)(nil).ListProvisionerAccounts), arg0, arg1) +} + // ListServiceAccounts mocks base method. func (m *MockStore) ListServiceAccounts(arg0 context.Context, arg1 db.ListServiceAccountsParams) ([]*db.Account, error) { m.ctrl.T.Helper() @@ -288,6 +392,21 @@ func (mr *MockStoreMockRecorder) StoreInstanceIdentityDocument(arg0, arg1 interf return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreInstanceIdentityDocument", reflect.TypeOf((*MockStore)(nil).StoreInstanceIdentityDocument), arg0, arg1) } +// TxCreateProvisionerAccount mocks base method. +func (m *MockStore) TxCreateProvisionerAccount(arg0 context.Context, arg1 db.CreateProvisionerAccountParams, arg2 db.StoreInstanceIdentityDocumentParams) (*db.Provisioner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TxCreateProvisionerAccount", arg0, arg1, arg2) + ret0, _ := ret[0].(*db.Provisioner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TxCreateProvisionerAccount indicates an expected call of TxCreateProvisionerAccount. +func (mr *MockStoreMockRecorder) TxCreateProvisionerAccount(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxCreateProvisionerAccount", reflect.TypeOf((*MockStore)(nil).TxCreateProvisionerAccount), arg0, arg1, arg2) +} + // TxCreateServiceAccount mocks base method. func (m *MockStore) TxCreateServiceAccount(arg0 context.Context, arg1 db.CreateServiceAccountParams, arg2 db.StoreInstanceIdentityDocumentParams) (*db.Account, error) { m.ctrl.T.Helper() @@ -303,6 +422,20 @@ func (mr *MockStoreMockRecorder) TxCreateServiceAccount(arg0, arg1, arg2 interfa return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxCreateServiceAccount", reflect.TypeOf((*MockStore)(nil).TxCreateServiceAccount), arg0, arg1, arg2) } +// TxDeleteProvisionerAccount mocks base method. +func (m *MockStore) TxDeleteProvisionerAccount(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TxDeleteProvisionerAccount", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// TxDeleteProvisionerAccount indicates an expected call of TxDeleteProvisionerAccount. +func (mr *MockStoreMockRecorder) TxDeleteProvisionerAccount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxDeleteProvisionerAccount", reflect.TypeOf((*MockStore)(nil).TxDeleteProvisionerAccount), arg0, arg1) +} + // TxDeleteServiceAccount mocks base method. func (m *MockStore) TxDeleteServiceAccount(arg0 context.Context, arg1 uuid.UUID) error { m.ctrl.T.Helper() diff --git a/db/query/accounts.sql b/db/query/accounts.sql index 4dd6386..aa27958 100644 --- a/db/query/accounts.sql +++ b/db/query/accounts.sql @@ -12,11 +12,12 @@ INSERT INTO accounts ( extended_key, certificate_validity, subordinate_ca, + provisioned, node_attestation, created_at, created_by ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16 ) RETURNING *; -- name: GetServiceUUID :one @@ -58,4 +59,12 @@ RETURNING *; -- name: DeleteServiceAccount :exec DELETE FROM accounts -WHERE client_id = $1; \ No newline at end of file +WHERE client_id = $1; + +-- name: GetServiceAccountBySAN :many +SELECT * FROM accounts +WHERE valid_subject_alternate_name = ANY($1::string[]); + +-- name: GetServiceAccountByMetadata :many +SELECT * FROM accounts +WHERE service_account LIKE $1 AND environment LIKE $2 AND extended_key LIKE $3; diff --git a/db/query/certificate.sql b/db/query/certificate.sql index df9ae48..56d00a3 100644 --- a/db/query/certificate.sql +++ b/db/query/certificate.sql @@ -32,4 +32,8 @@ OFFSET $2; -- name: RevokeIssuedCertificateSerialNumber :exec UPDATE certificates SET revoked = TRUE, revoke_date = $2, revoked_by = $3 -WHERE serial_number = $1; \ No newline at end of file +WHERE serial_number = $1; + +-- name: GetSignedCertificateByMetadata :many +SELECT * FROM certificates +WHERE serial_number LIKE $1 AND account LIKE $2 AND environment LIKE $3 AND extended_key LIKE $4; \ No newline at end of file diff --git a/db/query/provisioners.sql b/db/query/provisioners.sql index e69de29..1bbcd29 100644 --- a/db/query/provisioners.sql +++ b/db/query/provisioners.sql @@ -0,0 +1,32 @@ +-- name: CreateProvisionerAccount :one +INSERT INTO provisioners ( + client_id, + api_token, + provisioner_account, + environments, + team, + email, + regular_expression, + node_attestation, + valid_subject_alternate_names, + extended_keys, + max_certificate_validity, + created_at, + created_by +) VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 +) RETURNING *; + +-- name: GetProvisionerUUID :one +SELECT * FROM provisioners +WHERE client_id = $1; + +-- name: DeleteProvisionerAccount :exec +DELETE FROM provisioners +WHERE client_id = $1; + +-- name: ListProvisionerAccounts :many +SELECT * FROM provisioners +ORDER BY provisioners +LIMIT $1 +OFFSET $2; \ No newline at end of file diff --git a/db/sqlc/accounts.sql.go b/db/sqlc/accounts.sql.go index ce82f5a..a4bd797 100644 --- a/db/sqlc/accounts.sql.go +++ b/db/sqlc/accounts.sql.go @@ -28,12 +28,13 @@ INSERT INTO accounts ( extended_key, certificate_validity, subordinate_ca, + provisioned, node_attestation, created_at, created_by ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15 -) RETURNING client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, node_attestation, created_at, created_by + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16 +) RETURNING client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by ` type CreateServiceAccountParams struct { @@ -49,6 +50,7 @@ type CreateServiceAccountParams struct { ExtendedKey string `json:"extended_key"` CertificateValidity int16 `json:"certificate_validity"` SubordinateCa string `json:"subordinate_ca"` + Provisioned bool `json:"provisioned"` NodeAttestation []string `json:"node_attestation"` CreatedAt time.Time `json:"created_at"` CreatedBy uuid.UUID `json:"created_by"` @@ -68,6 +70,7 @@ func (q *Queries) CreateServiceAccount(ctx context.Context, arg CreateServiceAcc arg.ExtendedKey, arg.CertificateValidity, arg.SubordinateCa, + arg.Provisioned, pq.Array(arg.NodeAttestation), arg.CreatedAt, arg.CreatedBy, @@ -86,6 +89,7 @@ func (q *Queries) CreateServiceAccount(ctx context.Context, arg CreateServiceAcc &i.ExtendedKey, &i.CertificateValidity, &i.SubordinateCa, + &i.Provisioned, pq.Array(&i.NodeAttestation), &i.CreatedAt, &i.CreatedBy, @@ -103,8 +107,104 @@ func (q *Queries) DeleteServiceAccount(ctx context.Context, clientID uuid.UUID) return err } +const getServiceAccountByMetadata = `-- name: GetServiceAccountByMetadata :many +SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by FROM accounts +WHERE service_account LIKE $1 AND environment LIKE $2 AND extended_key LIKE $3 +` + +type GetServiceAccountByMetadataParams struct { + ServiceAccount string `json:"service_account"` + Environment string `json:"environment"` + ExtendedKey string `json:"extended_key"` +} + +func (q *Queries) GetServiceAccountByMetadata(ctx context.Context, arg GetServiceAccountByMetadataParams) ([]*Account, error) { + rows, err := q.db.QueryContext(ctx, getServiceAccountByMetadata, arg.ServiceAccount, arg.Environment, arg.ExtendedKey) + if err != nil { + return nil, err + } + defer rows.Close() + items := []*Account{} + for rows.Next() { + var i Account + if err := rows.Scan( + &i.ClientID, + &i.ApiToken, + &i.ServiceAccount, + &i.Environment, + &i.Team, + &i.Email, + &i.RegularExpression, + pq.Array(&i.ValidSubjectAlternateName), + pq.Array(&i.ValidCertificateAuthorities), + &i.ExtendedKey, + &i.CertificateValidity, + &i.SubordinateCa, + &i.Provisioned, + pq.Array(&i.NodeAttestation), + &i.CreatedAt, + &i.CreatedBy, + ); err != nil { + return nil, err + } + items = append(items, &i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getServiceAccountBySAN = `-- name: GetServiceAccountBySAN :many +SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by FROM accounts +WHERE valid_subject_alternate_name = ANY($1::string[]) +` + +func (q *Queries) GetServiceAccountBySAN(ctx context.Context, dollar_1 []string) ([]*Account, error) { + rows, err := q.db.QueryContext(ctx, getServiceAccountBySAN, pq.Array(dollar_1)) + if err != nil { + return nil, err + } + defer rows.Close() + items := []*Account{} + for rows.Next() { + var i Account + if err := rows.Scan( + &i.ClientID, + &i.ApiToken, + &i.ServiceAccount, + &i.Environment, + &i.Team, + &i.Email, + &i.RegularExpression, + pq.Array(&i.ValidSubjectAlternateName), + pq.Array(&i.ValidCertificateAuthorities), + &i.ExtendedKey, + &i.CertificateValidity, + &i.SubordinateCa, + &i.Provisioned, + pq.Array(&i.NodeAttestation), + &i.CreatedAt, + &i.CreatedBy, + ); err != nil { + return nil, err + } + items = append(items, &i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getServiceAccounts = `-- name: GetServiceAccounts :many -SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, node_attestation, created_at, created_by FROM accounts +SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by FROM accounts WHERE service_account = $1 ` @@ -130,6 +230,7 @@ func (q *Queries) GetServiceAccounts(ctx context.Context, serviceAccount string) &i.ExtendedKey, &i.CertificateValidity, &i.SubordinateCa, + &i.Provisioned, pq.Array(&i.NodeAttestation), &i.CreatedAt, &i.CreatedBy, @@ -148,7 +249,7 @@ func (q *Queries) GetServiceAccounts(ctx context.Context, serviceAccount string) } const getServiceUUID = `-- name: GetServiceUUID :one -SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, node_attestation, created_at, created_by FROM accounts +SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by FROM accounts WHERE client_id = $1 ` @@ -168,6 +269,7 @@ func (q *Queries) GetServiceUUID(ctx context.Context, clientID uuid.UUID) (*Acco &i.ExtendedKey, &i.CertificateValidity, &i.SubordinateCa, + &i.Provisioned, pq.Array(&i.NodeAttestation), &i.CreatedAt, &i.CreatedBy, @@ -176,7 +278,7 @@ func (q *Queries) GetServiceUUID(ctx context.Context, clientID uuid.UUID) (*Acco } const listServiceAccounts = `-- name: ListServiceAccounts :many -SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, node_attestation, created_at, created_by FROM accounts +SELECT client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by FROM accounts ORDER BY service_account LIMIT $1 OFFSET $2 @@ -209,6 +311,7 @@ func (q *Queries) ListServiceAccounts(ctx context.Context, arg ListServiceAccoun &i.ExtendedKey, &i.CertificateValidity, &i.SubordinateCa, + &i.Provisioned, pq.Array(&i.NodeAttestation), &i.CreatedAt, &i.CreatedBy, @@ -231,7 +334,7 @@ UPDATE accounts SET node_attestation = $2 WHERE client_id = $1 -RETURNING client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, node_attestation, created_at, created_by +RETURNING client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by ` type UpdateInstanceIdentityNodeAttestorParams struct { @@ -255,6 +358,7 @@ func (q *Queries) UpdateInstanceIdentityNodeAttestor(ctx context.Context, arg Up &i.ExtendedKey, &i.CertificateValidity, &i.SubordinateCa, + &i.Provisioned, pq.Array(&i.NodeAttestation), &i.CreatedAt, &i.CreatedBy, @@ -276,7 +380,7 @@ SET subordinate_ca = $10, node_attestation = $11 WHERE client_id = $1 -RETURNING client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, node_attestation, created_at, created_by +RETURNING client_id, api_token, service_account, environment, team, email, regular_expression, valid_subject_alternate_name, valid_certificate_authorities, extended_key, certificate_validity, subordinate_ca, provisioned, node_attestation, created_at, created_by ` type UpdateServiceAccountParams struct { @@ -321,6 +425,7 @@ func (q *Queries) UpdateServiceAccount(ctx context.Context, arg UpdateServiceAcc &i.ExtendedKey, &i.CertificateValidity, &i.SubordinateCa, + &i.Provisioned, pq.Array(&i.NodeAttestation), &i.CreatedAt, &i.CreatedBy, diff --git a/db/sqlc/certificate.sql.go b/db/sqlc/certificate.sql.go index 33a10c9..74191cf 100644 --- a/db/sqlc/certificate.sql.go +++ b/db/sqlc/certificate.sql.go @@ -38,6 +38,59 @@ func (q *Queries) GetCertificate(ctx context.Context, serialNumber string) (*Cer return &i, err } +const getSignedCertificateByMetadata = `-- name: GetSignedCertificateByMetadata :many +SELECT serial_number, account, environment, extended_key, common_name, subject_alternative_name, expiration_date, issued_date, revoked, revoked_by, revoke_date, certificate_authority_arn FROM certificates +WHERE serial_number LIKE $1 AND account LIKE $2 AND environment LIKE $3 AND extended_key LIKE $4 +` + +type GetSignedCertificateByMetadataParams struct { + SerialNumber string `json:"serial_number"` + Account string `json:"account"` + Environment string `json:"environment"` + ExtendedKey string `json:"extended_key"` +} + +func (q *Queries) GetSignedCertificateByMetadata(ctx context.Context, arg GetSignedCertificateByMetadataParams) ([]*Certificate, error) { + rows, err := q.db.QueryContext(ctx, getSignedCertificateByMetadata, + arg.SerialNumber, + arg.Account, + arg.Environment, + arg.ExtendedKey, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []*Certificate{} + for rows.Next() { + var i Certificate + if err := rows.Scan( + &i.SerialNumber, + &i.Account, + &i.Environment, + &i.ExtendedKey, + &i.CommonName, + pq.Array(&i.SubjectAlternativeName), + &i.ExpirationDate, + &i.IssuedDate, + &i.Revoked, + &i.RevokedBy, + &i.RevokeDate, + &i.CertificateAuthorityArn, + ); err != nil { + return nil, err + } + items = append(items, &i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const listCertificateSubjectAlternativeName = `-- name: ListCertificateSubjectAlternativeName :many SELECT serial_number, account, environment, extended_key, common_name, subject_alternative_name, expiration_date, issued_date, revoked, revoked_by, revoke_date, certificate_authority_arn FROM certificates WHERE common_name = $1 OR $1 = ANY(subject_alternative_name) diff --git a/db/sqlc/common.go b/db/sqlc/common.go index 172e4ca..36541dd 100644 --- a/db/sqlc/common.go +++ b/db/sqlc/common.go @@ -3,9 +3,10 @@ package db import "github.com/coinbase/baseca/internal/types" type CertificateResponseData struct { - Certificate string `json:"certificate"` - CertificateChain string `json:"certificate_chain,omitempty"` - Metadata types.CertificateMetadata `json:"metadata"` + Certificate string `json:"certificate"` + IntermediateCertificateChain string `json:"intermediate_certificate_chain,omitempty"` + RootCertificateChain string `json:"root_certificate_chain,omitempty"` + Metadata types.CertificateMetadata `json:"metadata"` } type DatabaseEndpoints struct { @@ -17,3 +18,8 @@ type CachedServiceAccount struct { ServiceAccount Account `json:"service_account"` AwsIid AwsAttestation `json:"aws_iid"` } + +type CachedProvisionerAccount struct { + ProvisionerAccount Provisioner `json:"provisioner_account"` + AwsIid AwsAttestation `json:"aws_iid"` +} diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 74b3c5a..4853649 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -25,6 +25,7 @@ type Account struct { ExtendedKey string `json:"extended_key"` CertificateValidity int16 `json:"certificate_validity"` SubordinateCa string `json:"subordinate_ca"` + Provisioned bool `json:"provisioned"` NodeAttestation []string `json:"node_attestation"` CreatedAt time.Time `json:"created_at"` CreatedBy uuid.UUID `json:"created_by"` @@ -67,6 +68,7 @@ type Provisioner struct { ValidSubjectAlternateNames []string `json:"valid_subject_alternate_names"` ExtendedKeys []string `json:"extended_keys"` MaxCertificateValidity int16 `json:"max_certificate_validity"` + NodeAttestation []string `json:"node_attestation"` CreatedAt time.Time `json:"created_at"` CreatedBy uuid.UUID `json:"created_by"` } diff --git a/db/sqlc/provisioners.sql.go b/db/sqlc/provisioners.sql.go new file mode 100644 index 0000000..cb128f6 --- /dev/null +++ b/db/sqlc/provisioners.sql.go @@ -0,0 +1,171 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 +// source: provisioners.sql + +package db + +import ( + "context" + "database/sql" + "time" + + "github.com/google/uuid" + "github.com/lib/pq" +) + +const createProvisionerAccount = `-- name: CreateProvisionerAccount :one +INSERT INTO provisioners ( + client_id, + api_token, + provisioner_account, + environments, + team, + email, + regular_expression, + node_attestation, + valid_subject_alternate_names, + extended_keys, + max_certificate_validity, + created_at, + created_by +) VALUES ( + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 +) RETURNING client_id, api_token, provisioner_account, environments, team, email, regular_expression, valid_subject_alternate_names, extended_keys, max_certificate_validity, node_attestation, created_at, created_by +` + +type CreateProvisionerAccountParams struct { + ClientID uuid.UUID `json:"client_id"` + ApiToken string `json:"api_token"` + ProvisionerAccount string `json:"provisioner_account"` + Environments []string `json:"environments"` + Team string `json:"team"` + Email string `json:"email"` + RegularExpression sql.NullString `json:"regular_expression"` + NodeAttestation []string `json:"node_attestation"` + ValidSubjectAlternateNames []string `json:"valid_subject_alternate_names"` + ExtendedKeys []string `json:"extended_keys"` + MaxCertificateValidity int16 `json:"max_certificate_validity"` + CreatedAt time.Time `json:"created_at"` + CreatedBy uuid.UUID `json:"created_by"` +} + +func (q *Queries) CreateProvisionerAccount(ctx context.Context, arg CreateProvisionerAccountParams) (*Provisioner, error) { + row := q.db.QueryRowContext(ctx, createProvisionerAccount, + arg.ClientID, + arg.ApiToken, + arg.ProvisionerAccount, + pq.Array(arg.Environments), + arg.Team, + arg.Email, + arg.RegularExpression, + pq.Array(arg.NodeAttestation), + pq.Array(arg.ValidSubjectAlternateNames), + pq.Array(arg.ExtendedKeys), + arg.MaxCertificateValidity, + arg.CreatedAt, + arg.CreatedBy, + ) + var i Provisioner + err := row.Scan( + &i.ClientID, + &i.ApiToken, + &i.ProvisionerAccount, + pq.Array(&i.Environments), + &i.Team, + &i.Email, + &i.RegularExpression, + pq.Array(&i.ValidSubjectAlternateNames), + pq.Array(&i.ExtendedKeys), + &i.MaxCertificateValidity, + pq.Array(&i.NodeAttestation), + &i.CreatedAt, + &i.CreatedBy, + ) + return &i, err +} + +const deleteProvisionerAccount = `-- name: DeleteProvisionerAccount :exec +DELETE FROM provisioners +WHERE client_id = $1 +` + +func (q *Queries) DeleteProvisionerAccount(ctx context.Context, clientID uuid.UUID) error { + _, err := q.db.ExecContext(ctx, deleteProvisionerAccount, clientID) + return err +} + +const getProvisionerUUID = `-- name: GetProvisionerUUID :one +SELECT client_id, api_token, provisioner_account, environments, team, email, regular_expression, valid_subject_alternate_names, extended_keys, max_certificate_validity, node_attestation, created_at, created_by FROM provisioners +WHERE client_id = $1 +` + +func (q *Queries) GetProvisionerUUID(ctx context.Context, clientID uuid.UUID) (*Provisioner, error) { + row := q.db.QueryRowContext(ctx, getProvisionerUUID, clientID) + var i Provisioner + err := row.Scan( + &i.ClientID, + &i.ApiToken, + &i.ProvisionerAccount, + pq.Array(&i.Environments), + &i.Team, + &i.Email, + &i.RegularExpression, + pq.Array(&i.ValidSubjectAlternateNames), + pq.Array(&i.ExtendedKeys), + &i.MaxCertificateValidity, + pq.Array(&i.NodeAttestation), + &i.CreatedAt, + &i.CreatedBy, + ) + return &i, err +} + +const listProvisionerAccounts = `-- name: ListProvisionerAccounts :many +SELECT client_id, api_token, provisioner_account, environments, team, email, regular_expression, valid_subject_alternate_names, extended_keys, max_certificate_validity, node_attestation, created_at, created_by FROM provisioners +ORDER BY provisioners +LIMIT $1 +OFFSET $2 +` + +type ListProvisionerAccountsParams struct { + Limit int32 `json:"limit"` + Offset int32 `json:"offset"` +} + +func (q *Queries) ListProvisionerAccounts(ctx context.Context, arg ListProvisionerAccountsParams) ([]*Provisioner, error) { + rows, err := q.db.QueryContext(ctx, listProvisionerAccounts, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + items := []*Provisioner{} + for rows.Next() { + var i Provisioner + if err := rows.Scan( + &i.ClientID, + &i.ApiToken, + &i.ProvisionerAccount, + pq.Array(&i.Environments), + &i.Team, + &i.Email, + &i.RegularExpression, + pq.Array(&i.ValidSubjectAlternateNames), + pq.Array(&i.ExtendedKeys), + &i.MaxCertificateValidity, + pq.Array(&i.NodeAttestation), + &i.CreatedAt, + &i.CreatedBy, + ); err != nil { + return nil, err + } + items = append(items, &i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/db/sqlc/querier.go b/db/sqlc/querier.go index 2480f70..89a4079 100644 --- a/db/sqlc/querier.go +++ b/db/sqlc/querier.go @@ -11,18 +11,25 @@ import ( ) type Querier interface { + CreateProvisionerAccount(ctx context.Context, arg CreateProvisionerAccountParams) (*Provisioner, error) CreateServiceAccount(ctx context.Context, arg CreateServiceAccountParams) (*Account, error) CreateUser(ctx context.Context, arg CreateUserParams) (*User, error) DeleteInstanceIdentityDocument(ctx context.Context, clientID uuid.UUID) error + DeleteProvisionerAccount(ctx context.Context, clientID uuid.UUID) error DeleteServiceAccount(ctx context.Context, clientID uuid.UUID) error DeleteUser(ctx context.Context, username string) error GetCertificate(ctx context.Context, serialNumber string) (*Certificate, error) GetInstanceIdentityDocument(ctx context.Context, clientID uuid.UUID) (*AwsAttestation, error) + GetProvisionerUUID(ctx context.Context, clientID uuid.UUID) (*Provisioner, error) + GetServiceAccountByMetadata(ctx context.Context, arg GetServiceAccountByMetadataParams) ([]*Account, error) + GetServiceAccountBySAN(ctx context.Context, dollar_1 []string) ([]*Account, error) GetServiceAccounts(ctx context.Context, serviceAccount string) ([]*Account, error) GetServiceUUID(ctx context.Context, clientID uuid.UUID) (*Account, error) + GetSignedCertificateByMetadata(ctx context.Context, arg GetSignedCertificateByMetadataParams) ([]*Certificate, error) GetUser(ctx context.Context, username string) (*User, error) ListCertificateSubjectAlternativeName(ctx context.Context, arg ListCertificateSubjectAlternativeNameParams) ([]*Certificate, error) ListCertificates(ctx context.Context, arg ListCertificatesParams) ([]*Certificate, error) + ListProvisionerAccounts(ctx context.Context, arg ListProvisionerAccountsParams) ([]*Provisioner, error) ListServiceAccounts(ctx context.Context, arg ListServiceAccountsParams) ([]*Account, error) ListUsers(ctx context.Context, arg ListUsersParams) ([]*User, error) LogCertificate(ctx context.Context, arg LogCertificateParams) (*Certificate, error) diff --git a/db/sqlc/store.go b/db/sqlc/store.go index 8d61a5b..d02ee4e 100644 --- a/db/sqlc/store.go +++ b/db/sqlc/store.go @@ -14,6 +14,8 @@ type Store interface { TxCreateServiceAccount(ctx context.Context, arg CreateServiceAccountParams, iid StoreInstanceIdentityDocumentParams) (*Account, error) TxDeleteServiceAccount(ctx context.Context, client_id uuid.UUID) error TxUpdateServiceAccount(ctx context.Context, arg Account, attestation types.NodeAttestation) (*Account, error) + TxCreateProvisionerAccount(ctx context.Context, arg CreateProvisionerAccountParams, iid StoreInstanceIdentityDocumentParams) (*Provisioner, error) + TxDeleteProvisionerAccount(ctx context.Context, client_id uuid.UUID) error } type SQLStore struct { db *sql.DB diff --git a/db/sqlc/tx_provisioner_account.go b/db/sqlc/tx_provisioner_account.go new file mode 100644 index 0000000..8bcc741 --- /dev/null +++ b/db/sqlc/tx_provisioner_account.go @@ -0,0 +1,51 @@ +package db + +import ( + "context" + + "github.com/google/uuid" +) + +func (store *SQLStore) TxCreateProvisionerAccount(ctx context.Context, arg CreateProvisionerAccountParams, iid StoreInstanceIdentityDocumentParams) (*Provisioner, error) { + var provisionerAccountResponse *Provisioner + + err := store.execTx(ctx, func(q *Queries) error { + var err error + + provisionerAccountResponse, err = store.CreateProvisionerAccount(ctx, arg) + if err != nil { + return err + } + + for _, node_attestation := range arg.NodeAttestation { + switch node_attestation { + case "AWS_IID": + // Add to AWS_IID Database + _, err = store.StoreInstanceIdentityDocument(ctx, iid) + if err != nil { + return err + } + } + } + return nil + }) + return provisionerAccountResponse, err +} + +func (store *SQLStore) TxDeleteProvisionerAccount(ctx context.Context, client_id uuid.UUID) error { + err := store.execTx(ctx, func(q *Queries) error { + var err error + + err = store.DeleteInstanceIdentityDocument(ctx, client_id) + if err != nil { + return err + } + + err = store.DeleteProvisionerAccount(ctx, client_id) + if err != nil { + return err + } + return err + }) + return err +} diff --git a/docs/ENDPOINTS.md b/docs/ENDPOINTS.md index e4a6699..356ac20 100644 --- a/docs/ENDPOINTS.md +++ b/docs/ENDPOINTS.md @@ -9,6 +9,7 @@ service Certificate { rpc ListCertificates (ListCertificatesRequest) returns (CertificatesParameter); rpc RevokeCertificate (RevokeCertificateRequest) returns (RevokeCertificateResponse); rpc OperationsSignCSR (OperationsSignRequest) returns (SignedCertificate); + rpc QueryCertificateMetadata (QueryCertificateMetadataRequest) returns (CertificatesParameter); } ``` @@ -17,10 +18,15 @@ service Certificate { ```protobuf service Service { rpc CreateServiceAccount (CreateServiceAccountRequest) returns (CreateServiceAccountResponse); + rpc CreateProvisionerAccount(CreateProvisionerAccountRequest) returns (CreateProvisionerAccountResponse); + rpc GetProvisionerAccount (AccountId) returns (ProvisionerAccount); + rpc GetServiceAccount (AccountId) returns (ServiceAccount); + rpc GetServiceAccountMetadata (GetServiceAccountMetadataRequest) returns (ServiceAccounts); + rpc DeleteServiceAccount (AccountId) returns (google.protobuf.Empty); + rpc DeleteProvisionedServiceAccount (AccountId) returns (google.protobuf.Empty); + rpc ProvisionServiceAccount (ProvisionServiceAccountRequest) returns (ProvisionServiceAccountResponse); rpc ListServiceAccounts (QueryParameter) returns (ServiceAccounts); - rpc GetServiceAccount (ServiceAccountId) returns (ServiceAccount); - rpc GetServiceAccountByName (ServiceAccountName) returns (ServiceAccounts); - rpc DeleteServiceAccount (ServiceAccountId) returns (google.protobuf.Empty); + rpc ListProvisionerAccounts (QueryParameter) returns (ProvisionerAccounts); } ``` @@ -49,6 +55,12 @@ rpc SignCSR (CertificateSigningRequest) returns (SignedCertificate); **Description** Sign Certificate Signing Request (CSR) +**Authentication** +Service Account Authentication + +**Client Example** +[sign_csr.go](../examples/certificate/baseca.v1.Certificate/sign_csr.go) + **Request** ```protobuf @@ -62,9 +74,11 @@ message CertificateSigningRequest { ```protobuf message SignedCertificate { string certificate = 1; - string certificate_chain = 2; - CertificateParameter metadata = 3; + string intermediate_certificate_chain = 2; + string root_certificate_chain = 3; + CertificateParameter metadata = 4; } + message CertificateParameter { string serial_number = 1; string common_name = 2; @@ -82,7 +96,8 @@ message CertificateParameter { ```json { "certificate": "-----BEGIN CERTIFICATE-----", - "certificate_chain": "-----BEGIN CERTIFICATE-----", + "intermediate_certificate_chain": "-----BEGIN CERTIFICATE-----", + "root_certificate_chain": "-----BEGIN CERTIFICATE-----", "metadata": { "serial_number": "4c15b9ec07c2779f5319ab68ea16b7fc5f452f36", "common_name": "sandbox.example.com", @@ -104,6 +119,47 @@ message CertificateParameter { } ``` +### **baseca.v1.Certificate/QueryCertificateMetadata** + +```protobuf +rpc QueryCertificateMetadata (QueryCertificateMetadataRequest) returns (CertificatesParameter); +``` + +**Description** +Query for Non-Ephemeral Certificate Issued from Provisioner, Certificates Issued from `baseca.v1.Certificate/SignCSR` are Excluded + +**Authentication** +Provisioner Account Authentication + +**Request** + +```protobuf +message QueryMetadataRequest { + string serial_number = 1; + string account = 2; + string environment = 3; + string extended_key = 4; + repeated string subject_alternative_name = 5; +} +``` + +**Response** + +```protobuf +message CertificatesParameter { + repeated CertificateParameter certificates = 1; +} + +message CertificateAuthorityParameter { + string region = 1; + string ca_arn = 2; + string sign_algorithm = 3; + bool assume_role = 4; + string role_arn = 5; + int32 validity = 6; +} +``` + ### **baseca.v1.Certificate/GetCertificate** ```protobuf @@ -113,6 +169,9 @@ rpc GetCertificate (CertificateSerialNumber) returns (CertificateParameter); **Description** Query Issued Certificate Metadata from Database +**Authentication** +User Authentication + **Request** ```protobuf @@ -152,17 +211,9 @@ message CertificateParameter { "serial_number": "4c15b9ec07c2779f5319ab68ea16b7fc5f452f36", "common_name": "sandbox.example.com", "subject_alternative_name": ["test.example.com"], - "expiration_date": { - "seconds": 1685128356, - "nanos": 876043203 - }, - "issued_date": { - "seconds": 1682536356, - "nanos": 876043115 - }, - "revoke_date": { - "seconds": -62135596800 - }, + "expiration_date": "2023-09-25T03:30:11Z", + "issued_date": "2023-08-25T03:30:11Z", + "revoke_date": "0001-01-01T00:00:00Z", "ca_serial_number": "50919db8e90a157cb5d44f8b1eb87879", "certificate_authority_arn": "arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/11111111-22222-3333-4444-555555555555" } @@ -178,6 +229,9 @@ rpc ListCertificates (ListCertificatesRequest) returns (CertificatesParameter); **Description** List Issued Certificates via Common Name (CN) +**Authentication** +User Authentication + **Request** ```protobuf @@ -214,7 +268,7 @@ message CertificateAuthorityParameter { } ``` -### **baseca.v1.Certificate/RevokeCertificateRequest** +### **baseca.v1.Certificate/RevokeCertificate** ```protobuf rpc RevokeCertificate (RevokeCertificateRequest) returns (RevokeCertificateResponse); @@ -223,6 +277,9 @@ rpc RevokeCertificate (RevokeCertificateRequest) returns (RevokeCertificateRespo **Description** Revoke Subordinate CA Certificate from ACM Private CA +**Authentication** +User Authentication + **Request** ```protobuf @@ -230,6 +287,9 @@ message RevokeCertificateRequest { string serial_number = 1; string revocation_reason = 2; } +``` + +``` AFFILIATION_CHANGED CESSATION_OF_OPERATION A_A_COMPROMISE @@ -276,33 +336,22 @@ rpc OperationsSignCSR (OperationsSignRequest) returns (SignedCertificate); **Description** Manual Sign Certificate Signing Request (CSR) +**Authentication** +Provisioner Account Authentication + +**Client Example** +[operations_sign_csr.go](../examples/certificate/baseca.v1.Certificate/operations_sign_csr.go) + **Request** ```protobuf message OperationsSignRequest { string certificate_signing_request = 1; - CertificateAuthorityParameter certificate_authority = 2; + optional CertificateAuthorityParameter certificate_authority = 2; string service_account = 3; string environment = 4; - string extended_key = 5;} -``` - -```sh -grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ - -d '{ - "certificate_signing_request": "-----BEGIN CERTIFICATE REQUEST-----", - "certificate_authority": { - "region": "us-east-1", - "ca_arn": "arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/11111111-22222-3333-4444-555555555555", - "sign_algorithm": "SHA512WITHRSA", - "assume_role": "false", - "validity": "30" - }, - "service_account": "example", - "environment": "development", - "extended_key": "EndEntityServerAuthCertificate" - }' \ - localhost:9090 baseca.v1.Certificate/OperationsSignCSR + string extended_key = 5; +} ``` **Response** @@ -310,9 +359,11 @@ grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ ```protobuf message SignedCertificate { string certificate = 1; - string certificate_chain = 2; - CertificateParameter metadata = 3; + string intermediate_certificate_chain = 2; + string root_certificate_chain = 3; + CertificateParameter metadata = 4; } + message CertificateParameter { string serial_number = 1; string common_name = 2; @@ -339,6 +390,9 @@ rpc CreateServiceAccount (CreateServiceAccountRequest) returns (CreateServiceAcc **Description** Create Service Account Record +**Authentication** +User Authentication + **Request** ```protobuf @@ -383,7 +437,7 @@ grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ "extended_key": "EndEntityServerAuthCertificate", "node_attestation": { "aws_iid": { - "role_arn": "arn:aws:iam::123456789012:role/role", + "role_arn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", "assume_role": "arn:aws:iam::123456789012:role/assumed-role", "security_groups": ["sg-0123456789abcdef0"], "region": "us-east-1" @@ -433,7 +487,7 @@ message CreateServiceAccountResponse { "extendedKey": "EndEntityServerAuthCertificate", "nodeAttestation": { "awsIid": { - "roleArn": "arn:aws:iam::123456789012:role/role", + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", "securityGroups": ["sg-0123456789abcdef0"], "region": "us-east-1" @@ -457,6 +511,9 @@ rpc ListServiceAccounts (QueryParameter) returns (ServiceAccounts); **Description** Query Service Accounts from Database +**Authentication** +User Authentication + **Request** ```protobuf @@ -481,6 +538,7 @@ message QueryParameter { message ServiceAccounts { repeated ServiceAccount service_accounts = 1; } + message ServiceAccount { string client_id = 1; string service_account = 2; @@ -491,10 +549,12 @@ message ServiceAccount { string extended_key = 7; NodeAttestation node_attestation = 8; int32 certificate_validity = 9; - string team = 10; - string email = 11; - google.protobuf.Timestamp created_at = 12; - string created_by = 13; + string subordinate_ca = 10; + bool provisioned = 11; + string team = 12; + string email = 13; + google.protobuf.Timestamp created_at = 14; + string created_by = 15; } ``` @@ -510,13 +570,15 @@ message ServiceAccount { "extendedKey": "EndEntityServerAuthCertificate", "nodeAttestation": { "awsIid": { - "roleArn": "arn:aws:iam::123456789012:role/role", + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", "securityGroups": ["sg-0123456789abcdef0"], "region": "us-east-1" } }, "certificateValidity": 30, + "subordinate_ca": "infrastructure", + "provisioned": false, "team": "Infrastructure Security", "email": "security@coinbase.com", "createdAt": "2023-04-26T22:24:42.873116Z", @@ -526,98 +588,128 @@ message ServiceAccount { } ``` -### **baseca.v1.Service/GetServiceAccountUuid** +### **baseca.v1.Service/ListProvisionerAccounts** ```protobuf -rpc GetServiceAccountUuid (ServiceAccountId) returns (ServiceAccount); +rpc ListProvisionerAccounts (QueryParameter) returns (ProvisionerAccounts); ``` **Description** -Query Service Account from Database +List Provisioner Service Accounts **Request** ```protobuf -message ServiceAccountId { - string uuid = 1; +message QueryParameter { + int32 page_id = 2; + int32 page_size = 3; } ``` ```sh grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ -d '{ - "uuid": "585c2f84-9a0e-4775-827a-a0a99c7dddcc" + "page_id": 1, + "page_size": 25 }' \ - localhost:9090 baseca.v1.Service/GetServiceAccount + localhost:9090 baseca.v1.Service/ListProvisionerAccounts ``` **Response** ```protobuf -message ServiceAccount { +message ProvisionerAccounts { + repeated ProvisionerAccount provisioner_accounts = 1; +} + +message ProvisionerAccount { string client_id = 1; - string service_account = 2; - string environment = 3; + string provisioner_account = 2; + repeated string environments = 3; string regular_expression = 4; repeated string subject_alternative_names = 5; - repeated string certificate_authorities = 6; - string extended_key = 7; + repeated string extended_keys = 7; NodeAttestation node_attestation = 8; - int32 certificate_validity = 9; + uint32 max_certificate_validity = 9; string team = 10; string email = 11; google.protobuf.Timestamp created_at = 12; string created_by = 13; } + +message NodeAttestation { + AWSInstanceIdentityDocument aws_iid = 1; +} + +message AWSInstanceIdentityDocument { + string role_arn = 1; + string assume_role = 2; + repeated string security_groups = 3; + string region = 4; + string instance_id = 5; + string image_id = 6; + map instance_tags = 7; +} ``` ```json { - "clientId": "585c2f84-9a0e-4775-827a-a0a99c7dddcc", - "serviceAccount": "example", - "environment": "development", - "subjectAlternativeNames": ["development.coinbase.com"], - "certificateAuthorities": ["development_use1"], - "extendedKey": "EndEntityServerAuthCertificate", - "nodeAttestation": { - "awsIid": { - "roleArn": "arn:aws:iam::123456789012:role/role", - "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", - "securityGroups": ["sg-0123456789abcdef0"], - "region": "us-east-1" + "provisionerAccounts": [ + { + "clientId": "650b0ead-1c6b-49b3-810e-48d20a2890ac", + "provisionerAccount": "example", + "environments": ["development", "sandbox"], + "regularExpression": "[A-Za-z0-9.-]", + "subjectAlternativeNames": ["test.coinbase.com"], + "extendedKeys": ["EndEntityServerAuthCertificate"], + "nodeAttestation": { + "awsIid": { + "roleArn": "arn:aws:iam::123456789012:role/role", + "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", + "securityGroups": ["sg-0123456789abcdef0"], + "region": "us-east-1" + } + }, + "maxCertificateValidity": 30, + "team": "Security", + "email": "example@coinbase.com", + "createdAt": "2023-04-26T22:24:42.873116Z", + "createdBy": "830b9b81-37c0-4180-9dba-9f21b1f6ae21" } - }, - "certificateValidity": 30, - "team": "Infrastructure Security", - "email": "security@coinbase.com", - "createdAt": "2023-04-26T22:24:42.873116Z", - "createdBy": "830b9b81-37c0-4180-9dba-9f21b1f6ae21" + ] } ``` -### **baseca.v1.Service/GetServiceAccountName** +### **baseca.v1.Service/GetServiceAccountMetadata** ```protobuf -rpc GetServiceAccountName (ServiceAccountName) returns (ServiceAccounts); +rpc GetServiceAccountMetadata (GetServiceAccountMetadataRequest) returns (ServiceAccounts); ``` **Description** -Query Service Account from Database By Name +Query Service Account from Database via Metadata + +**Authentication** +User Authentication **Request** ```protobuf -message ServiceAccountName { +message GetServiceAccountMetadataRequest{ string service_account = 1; + string environment = 2; + string extended_key = 3; } ``` ```sh grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ -d '{ - "service_account": "example" + "service_account": "example", + "environment": "development", + "extended_key": "EndEntityServerAuthCertificate" }' \ - localhost:9090 baseca.v1.Service/GetServiceAccountByName + localhost:9090 baseca.v1.Service/GetServiceAccountMetadata ``` **Response** @@ -626,6 +718,7 @@ grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ message ServiceAccounts { repeated ServiceAccount service_accounts = 1; } + message ServiceAccount { string client_id = 1; string service_account = 2; @@ -636,10 +729,12 @@ message ServiceAccount { string extended_key = 7; NodeAttestation node_attestation = 8; int32 certificate_validity = 9; - string team = 10; - string email = 11; - google.protobuf.Timestamp created_at = 12; - string created_by = 13; + string subordinate_ca = 10; + bool provisioned = 11; + string team = 12; + string email = 13; + google.protobuf.Timestamp created_at = 14; + string created_by = 15; } ``` @@ -655,13 +750,15 @@ message ServiceAccount { "extendedKey": "EndEntityServerAuthCertificate", "nodeAttestation": { "awsIid": { - "roleArn": "arn:aws:iam::123456789012:role/role", + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", "securityGroups": ["sg-0123456789abcdef0"], "region": "us-east-1" } }, "certificateValidity": 30, + "subordinateCa": "infrastructure", + "provisioned": false, "team": "Infrastructure Security", "email": "security@coinbase.com", "createdAt": "2023-04-26T22:24:42.873116Z", @@ -671,19 +768,98 @@ message ServiceAccount { } ``` +### **baseca.v1.Service/GetServiceAccount** + +```protobuf +rpc GetServiceAccount (AccountId) returns (ServiceAccount); +``` + +**Description** +Query Service Account from Database By UUID + +**Authentication** +User Authentication + +**Request** + +```protobuf +message AccountId { + string uuid = 1; +} +``` + +```sh +grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ + -d '{ + "uuid": "585c2f84-9a0e-4775-827a-a0a99c7dddcc" + }' \ + localhost:9090 baseca.v1.Service/GetServiceAccount +``` + +**Response** + +```protobuf +message ServiceAccount { + string client_id = 1; + string service_account = 2; + string environment = 3; + string regular_expression = 4; + repeated string subject_alternative_names = 5; + repeated string certificate_authorities = 6; + string extended_key = 7; + NodeAttestation node_attestation = 8; + int32 certificate_validity = 9; + string subordinate_ca = 10; + bool provisioned = 11; + string team = 12; + string email = 13; + google.protobuf.Timestamp created_at = 14; + string created_by = 15; +} +``` + +```json +{ + "clientId": "585c2f84-9a0e-4775-827a-a0a99c7dddcc", + "serviceAccount": "example", + "environment": "development", + "subjectAlternativeNames": ["development.coinbase.com"], + "certificateAuthorities": ["development_use1"], + "extendedKey": "EndEntityServerAuthCertificate", + "nodeAttestation": { + "awsIid": { + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", + "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", + "securityGroups": ["sg-0123456789abcdef0"], + "region": "us-east-1" + } + }, + "certificateValidity": 30, + "subordinateCa": "infrastructure", + "provisioned": false, + "team": "Infrastructure Security", + "email": "security@coinbase.com", + "createdAt": "2023-04-26T22:24:42.873116Z", + "createdBy": "830b9b81-37c0-4180-9dba-9f21b1f6ae21" +} +``` + ### **baseca.v1.Service/DeleteServiceAccount** ```protobuf -rpc DeleteServiceAccount (ServiceAccountId) returns (google.protobuf.Empty); +rpc DeleteServiceAccount (AccountId) returns (google.protobuf.Empty); ``` **Description** Delete Service Account from Database +**Authentication** +User Authentication + **Request** ```protobuf -message ServiceAccountId { +message AccountId { string uuid = 1; } ``` @@ -702,6 +878,345 @@ grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ google.protobuf.Empty ``` +### **baseca.v1.Service/DeleteProvisionedServiceAccount** + +```protobuf +rpc DeleteProvisionedServiceAccount (AccountId) returns (google.protobuf.Empty); +``` + +**Description** +Delete Service Account Generated from Provisioner + +**Authentication** +Provisioner Account Authentication + +**Request** + +```protobuf +message AccountId { + string uuid = 1; +} +``` + +**Response** + +```protobuf +google.protobuf.Empty +``` + +### **baseca.v1.Service/CreateProvisionerAccount** + +```protobuf +rpc CreateProvisionerAccount (CreateProvisionerAccountRequest) returns (CreateProvisionerAccountResponse); +``` + +**Description** +Create Provisioner Account Record + +**Authentication** +User Authentication + +**Request** + +```protobuf +message CreateProvisionerAccountRequest { + string provisioner_account = 1; + repeated string environments = 2; + optional string regular_expression = 3; + repeated string subject_alternative_names = 4; + repeated string extended_keys = 5; + uint32 max_certificate_validity = 6; + optional NodeAttestation node_attestation = 7; + string team = 8; + string email = 9; +} + +message NodeAttestation { + AWSInstanceIdentityDocument aws_iid = 1; +} + +message AWSInstanceIdentityDocument { + string role_arn = 1; + string assume_role = 2; + repeated string security_groups = 3; + string region = 4; + string instance_id = 5; + string image_id = 6; + map instance_tags = 7; +} +``` + +```sh +grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ + -d '{ + "provisioner_account": "example", + "environments": ["development"], + "subject_alternative_names": [ + "development.coinbase.com" + ], + "extended_keys": ["EndEntityServerAuthCertificate"], + "node_attestation": { + "aws_iid": { + "role_arn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", + "assume_role": "arn:aws:iam::123456789012:role/assumed-role", + "security_groups": ["sg-0123456789abcdef0"], + "region": "us-east-1" + } + }, + "max_certificate_validity": 30, + "team": "Infrastructure Security", + "email": "security@coinbase.com" + }' \ + localhost:9090 baseca.v1.Service/CreateProvisionerAccount +``` + +**Response** + +```protobuf +message CreateProvisionerAccountResponse { + string client_id = 1; + string client_token = 2; + string provisioner_account = 3; + repeated string environments = 4; + string regular_expression = 5; + repeated string subject_alternative_names = 6; + repeated string extended_keys = 8; + NodeAttestation node_attestation = 9; + uint32 max_certificate_validity = 10; + string team = 11; + string email = 12; + google.protobuf.Timestamp created_at = 13; + string created_by = 14; +} +``` + +```json +{ + "clientId": "585c2f84-9a0e-4775-827a-a0a99c7dddcc", + "clientToken": "[CLIENT_TOKEN]", + "provisionerAccount": "example", + "environments": ["development"], + "subjectAlternativeNames": ["development.coinbase.com"], + "extendedKeys": ["EndEntityServerAuthCertificate"], + "nodeAttestation": { + "awsIid": { + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", + "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", + "securityGroups": ["sg-0123456789abcdef0"], + "region": "us-east-1" + } + }, + "maxCertificateValidity": 30, + "team": "Infrastructure Security", + "email": "security@coinbase.com", + "createdAt": "2023-04-26T22:24:42.873116Z", + "createdBy": "830b9b81-37c0-4180-9dba-9f21b1f6ae21" +} +``` + +### **baseca.v1.Service/GetProvisionerAccount** + +```protobuf +rpc GetProvisionerAccount (AccountId) returns (ProvisionerAccount); +``` + +**Description** +Query Provisioner Account + +**Authentication** +User Authentication + +**Request** + +```protobuf +message AccountId { + string uuid = 1; +} +``` + +```sh +grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ + -d '{ + "uuid": "ce337d41-f8b5-4630-b469-5ef896cf4fc1" + }' \ + localhost:9090 baseca.v1.Service/GetProvisionerAccount +``` + +**Response** + +```protobuf +message ProvisionerAccount { + string client_id = 1; + string provisioner_account = 2; + repeated string environments = 3; + string regular_expression = 4; + repeated string subject_alternative_names = 5; + repeated string extended_keys = 7; + NodeAttestation node_attestation = 8; + uint32 max_certificate_validity = 9; + string team = 10; + string email = 11; + google.protobuf.Timestamp created_at = 12; + string created_by = 13; +} +``` + +```json +{ + "clientId": "585c2f84-9a0e-4775-827a-a0a99c7dddcc", + "provisionerAccount": "example", + "environments": ["development"], + "subjectAlternativeNames": ["development.coinbase.com"], + "extendedKeys": ["EndEntityServerAuthCertificate"], + "nodeAttestation": { + "awsIid": { + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", + "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", + "securityGroups": ["sg-0123456789abcdef0"], + "region": "us-east-1" + } + }, + "maxCertificateValidity": 30, + "team": "Infrastructure Security", + "email": "security@coinbase.com", + "createdAt": "2023-04-26T22:24:42.873116Z", + "createdBy": "830b9b81-37c0-4180-9dba-9f21b1f6ae21" +} +``` + +### **baseca.v1.Service/ProvisionServiceAccount** + +```protobuf +rpc ProvisionServiceAccount (ProvisionServiceAccountRequest) returns (ProvisionServiceAccountResponse); +``` + +**Description** +Create Service Account Record + +**Authentication** +Provisioner Account Authentication + +**Request** + +```protobuf +message ProvisionServiceAccountRequest { + CreateServiceAccountRequest account = 1; +} + +message CreateServiceAccountRequest { + string service_account = 1; + string environment = 2; + optional string regular_expression = 3; + repeated string subject_alternative_names = 4; + repeated string certificate_authorities = 5; + string extended_key = 6; + int32 certificate_validity = 7; + string subordinate_ca = 8; + optional NodeAttestation node_attestation = 9; + string team = 10; + string email = 11; +} +message NodeAttestation { + AWSInstanceIdentityDocument aws_iid = 1; +} +message AWSInstanceIdentityDocument { + string role_arn = 1; + string assume_role = 2; + repeated string security_groups = 3; + string region = 4; + string instance_id = 5; + string image_id = 6; + map instance_tags = 7; +} +``` + +**Response** + +```protobuf +message ProvisionServiceAccountResponse { + CreateServiceAccountResponse account = 1; +} +message CreateServiceAccountResponse { + string client_id = 1; + string client_token = 2; + string service_account = 3; + string environment = 4; + string regular_expression = 5; + repeated string subject_alternative_names = 6; + repeated string certificate_authorities = 7; + string extended_key = 8; + NodeAttestation node_attestation = 9; + int32 certificate_validity = 10; + string subordinate_ca = 11; + string team = 12; + string email = 13; + google.protobuf.Timestamp created_at = 14; + string created_by = 15; +} +``` + +```json +{ + "account": { + "clientId": "585c2f84-9a0e-4775-827a-a0a99c7dddcc", + "clientToken": "[CLIENT_TOKEN]", + "serviceAccount": "example", + "environment": "development", + "subjectAlternativeNames": ["development.coinbase.com"], + "certificateAuthorities": ["cb_sandbox_use1_cbhq_net"], + "extendedKey": "EndEntityServerAuthCertificate", + "nodeAttestation": { + "awsIid": { + "roleArn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", + "assumeRole": "arn:aws:iam::123456789012:role/assumed-role", + "securityGroups": ["sg-0123456789abcdef0"], + "region": "us-east-1" + } + }, + "certificateValidity": 30, + "subordinateCa": "infrastructure", + "team": "Infrastructure Security", + "email": "security@coinbase.com", + "createdAt": "2023-04-26T22:24:42.873116Z", + "createdBy": "830b9b81-37c0-4180-9dba-9f21b1f6ae21" + } +} +``` + +### **baseca.v1.Service/DeleteProvisionerAccount** + +```protobuf +rpc DeleteProvisionerAccount (AccountId) returns (google.protobuf.Empty); +``` + +**Description** +Delete Provisioner Account from Database + +**Authentication** +User Authentication + +**Request** + +```protobuf +message AccountId { + string uuid = 1; +} +``` + +```sh +grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ + -d '{ + "uuid": "ce337d41-f8b5-4630-b469-5ef896cf4fc1" + }' \ + localhost:9090 baseca.v1.Service/DeleteProvisionerAccount +``` + +**Response** + +```protobuf +google.protobuf.Empty +``` + ## Account ### **baseca.v1.Account/LoginUser** @@ -711,7 +1226,10 @@ rpc LoginUser (LoginUserRequest) returns (LoginUserResponse); ``` **Description** -User Authentication, Returns JSON Web Token (JWT) +Returns JSON Web Token (JWT) for User Authentication Endpoints + +**Authentication** +None **Request** @@ -774,6 +1292,9 @@ rpc DeleteUser (UsernameRequest) returns (google.protobuf.Empty); **Description** Delete User from Database +**Authentication** +User Authentication + **Request** ```protobuf @@ -787,7 +1308,7 @@ grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ -d '{ "username": "example@coinbase.com" }' \ - localhost:9090 baseca.v1.Service/DeleteUser + localhost:9090 baseca.v1.Account/DeleteUser ``` **Response** @@ -805,6 +1326,9 @@ rpc GetUser (UsernameRequest) returns (User); **Description** Query User from Database +**Authentication** +User Authentication + **Request** ```protobuf @@ -816,7 +1340,7 @@ message UsernameRequest { ```sh grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ -d '{ - "username": "production_sample" + "username": "example@coinbase.com" }' \ localhost:9090 baseca.v1.Account/GetUser ``` @@ -856,6 +1380,9 @@ rpc ListUsers (QueryParameter) returns (Users); **Description** Query Users from Database +**Authentication** +User Authentication + **Request** ```protobuf @@ -925,6 +1452,9 @@ rpc CreateUser (CreateUserRequest) returns (User); **Description** Create User to Manually Interface with baseca Control Plane +**Authentication** +User Authentication + **Request** ```protobuf @@ -984,6 +1514,9 @@ rpc UpdateUserCredentials (UpdateCredentialsRequest) returns (User); **Description** Update User Password +**Authentication** +None + **Request** ```protobuf @@ -1027,6 +1560,9 @@ rpc UpdateUserPermissions (UpdatePermissionsRequest) returns (User); **Description** Update Permissions Parameter for User +**Authentication** +User Authentication + **Request** ```protobuf diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index a4a1ed9..991f4e5 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -171,7 +171,7 @@ Run the `baseca` Container **RELEASE:** Search for Latest [`baseca ghcr.io Published Release`](https://github.com/orgs/coinbase/packages/container/package/baseca) and update the `VERSION_SHA` container tag with the latest version. ```sh -docker run -p 9090:9090 -e password=secret -v ~/.aws/:/home/baseca/.aws/:ro \ +docker run -p 9090:9090 -e database_credentials=secret -v ~/.aws/:/home/baseca/.aws/:ro \ -v /path/to/baseca/config:/home/baseca/config ghcr.io/coinbase/baseca:VERSION_SHA ``` @@ -193,11 +193,11 @@ Compile the Golang Binary `baseca` ```sh # Darwin AMD64 GOOS=darwin GOARCH=amd64 go build -o target/bin/darwin/baseca cmd/server/main.go -password=secret ./target/bin/darwin/baseca +database_credentials=secret ./target/bin/darwin/baseca # Linux AMD64 GOOS=linux GOARCH=amd64 go build -o target/bin/linux/baseca cmd/server/main.go -password=secret ./target/bin/linux/baseca +database_credentials=secret ./target/bin/linux/baseca ``` ### 3c. Run baseca as One-Off Execution (Option C) diff --git a/docs/PRODUCTION_DEPLOYMENT.md b/docs/PRODUCTION_DEPLOYMENT.md index 89f27ff..53bd2cf 100644 --- a/docs/PRODUCTION_DEPLOYMENT.md +++ b/docs/PRODUCTION_DEPLOYMENT.md @@ -127,21 +127,16 @@ secrets_manager: secret_id: rds!cluster-bcc40600-5fa7-4877-aa35-529cae165937 ``` -### 2. Launch Temporary EC2 Instance - -A temporary `Ubuntu` EC2 instance with the requirements below will need to be deployed to perform the database migration. - -- Egress Port 80 to 0.0.0.0/0 -- Egress Port 5432 to 0.0.0.0/0 -- Ingress Port 22 from Local IP -- Deploy in Subnet Routable to RDS Cluster -- Private IP within `db_ingress_cidr` CIDR Block - -### 3. Perform Database Migration +### 2. Perform Database Migration [`golang-migrate Download Instructions`](https://github.com/golang-migrate/migrate/blob/master/cmd/migrate/README.md) +**NOTE:** The RDS Cluster should be deployed within a private subnet which means the database migration must be done through an EC2 instance which (a) has network connectivity to the database and (b) is allowed by the security group from the database over Port 5432. + ```sh +# Launch an Ubuntu EC2 Instance +# Documentation: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html + cd /path/to/baseca # Copy Database Migration Files and RDS Certificate to EC2 @@ -164,7 +159,7 @@ curl -L https://github.com/golang-migrate/migrate/releases/download/v4.16.1/migr error: parse "postgresql://baseca:[PASSWORD]@[RDS_WRITER_ENDPOINT]:5432/baseca?sslmode=disable": net/url: invalid userinfo ``` -### 4. Create Initial Admin User +### 3. Create Initial Admin User ```sh # Update db/init/init.sql for Admin User diff --git a/docs/SCOPE.md b/docs/SCOPE.md index 24f9c8a..5c04552 100644 --- a/docs/SCOPE.md +++ b/docs/SCOPE.md @@ -25,7 +25,7 @@ grpcurl -vv -plaintext -H "Authorization: Bearer ${AUTH_TOKEN}" \ "extended_key": "EndEntityServerAuthCertificate", "node_attestation": { # << Node Attestation Scope >> "aws_iid": { - "role_arn": "arn:aws:iam::123456789012:role/role", + "role_arn": "arn:aws:iam::123456789012:instance-profile/instance-profile-name", "assume_role": "arn:aws:iam::123456789012:role/assumed-role", "security_groups": ["sg-0123456789abcdef0"], "region": "us-east-1" diff --git a/examples/certificate/baseca.v1.Certificate/code_sign.go b/examples/certificate/baseca.v1.Certificate/code_sign.go index 427b870..a29b284 100644 --- a/examples/certificate/baseca.v1.Certificate/code_sign.go +++ b/examples/certificate/baseca.v1.Certificate/code_sign.go @@ -1,14 +1,14 @@ -package main +package examples import ( "crypto/x509" "fmt" - "io/ioutil" + "os" baseca "github.com/coinbase/baseca/pkg/client" ) -func main() { +func CodeSign() { client_id := "[CLIENT_ID]" client_token := "[CLIENT_TOKEN]" @@ -29,14 +29,15 @@ func main() { PublicKeyAlgorithm: x509.RSA, KeySize: 4096, Output: baseca.Output{ - PrivateKey: "/tmp/private.key", - Certificate: "/tmp/certificate.crt", - CertificateChain: "/tmp/certificate_chain.crt", - CertificateSigningRequest: "/tmp/certificate_request.csr", + PrivateKey: "/tmp/private.key", + Certificate: "/tmp/certificate.crt", + IntermediateCertificateChain: "/tmp/intermediate_chain.crt", + RootCertificateChain: "/tmp/root_chain.crt", + CertificateSigningRequest: "/tmp/certificate_request.csr", }, } - data, _ := ioutil.ReadFile("/bin/chmod") + data, _ := os.ReadFile("/bin/chmod") signature, chain, err := client.GenerateSignature(metadata, data) if err != nil { panic(err) diff --git a/examples/certificate/baseca.v1.Certificate/operations_sign_csr.go b/examples/certificate/baseca.v1.Certificate/operations_sign_csr.go new file mode 100644 index 0000000..25520f1 --- /dev/null +++ b/examples/certificate/baseca.v1.Certificate/operations_sign_csr.go @@ -0,0 +1,56 @@ +package examples + +import ( + "crypto/x509" + "fmt" + "log" + + apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" + baseca "github.com/coinbase/baseca/pkg/client" +) + +func OperationsSignCSR() { + client_id := "[CLIENT_ID]" + client_token := "[CLIENT_TOKEN]" + + configuration := baseca.Configuration{ + URL: "localhost:9090", + Environment: baseca.Env.Local, + } + + client, err := baseca.LoadDefaultConfiguration(configuration, client_id, client_token, baseca.Attestation.Local) + if err != nil { + fmt.Println(err) + } + + certAuth := apiv1.CertificateAuthorityParameter{ + Region: "us-east-1", + CaArn: "arn:aws:acm-pca:us-east-1:1123331122:certificate-authority/112311-111231-1123131-11231", + SignAlgorithm: "SHA512WITHRSA", + AssumeRole: false, + Validity: 30, + } + + certificateRequest := baseca.CertificateRequest{ + CommonName: "example.coinbase.com", + SubjectAlternateNames: []string{"example.coinbase.com"}, + SigningAlgorithm: x509.SHA384WithRSA, + PublicKeyAlgorithm: x509.RSA, + KeySize: 4096, + Output: baseca.Output{ + PrivateKey: "/tmp/sandbox.key", + CertificateSigningRequest: "/tmp/sandbox.csr", + Certificate: "/tmp/sandbox.crt", + IntermediateCertificateChain: "/tmp/intermediate_chain.crt", + RootCertificateChain: "/tmp/root_chain.crt", + }, + } + + res, err := client.ProvisionIssueCertificate(certificateRequest, &certAuth, "example", "development", "EndEntityServerAuthCertificate") + + if err != nil { + log.Fatal(err) + } + log.Printf("%+v", res) + +} diff --git a/examples/certificate/baseca.v1.Certificate/sign_csr.go b/examples/certificate/baseca.v1.Certificate/sign_csr.go index cdfcd57..8cb7833 100644 --- a/examples/certificate/baseca.v1.Certificate/sign_csr.go +++ b/examples/certificate/baseca.v1.Certificate/sign_csr.go @@ -1,4 +1,4 @@ -package main +package examples import ( "crypto/x509" @@ -8,7 +8,7 @@ import ( baseca "github.com/coinbase/baseca/pkg/client" ) -func main() { +func SignCSR() { client_id := "[CLIENT_ID]" client_token := "[CLIENT_TOKEN]" @@ -29,10 +29,11 @@ func main() { PublicKeyAlgorithm: x509.RSA, KeySize: 4096, Output: baseca.Output{ - PrivateKey: "/tmp/private.key", - Certificate: "/tmp/certificate.crt", - CertificateChain: "/tmp/certificate_chain.crt", - CertificateSigningRequest: "/tmp/certificate_request.csr", + PrivateKey: "/tmp/private.key", + Certificate: "/tmp/certificate.crt", + IntermediateCertificateChain: "/tmp/intermediate_chain.crt", + RootCertificateChain: "/tmp/root_chain.crt", + CertificateSigningRequest: "/tmp/certificate_request.csr", }, } diff --git a/gen/go/baseca/v1/api.pb.go b/gen/go/baseca/v1/api.pb.go index 467e58b..9d76759 100644 --- a/gen/go/baseca/v1/api.pb.go +++ b/gen/go/baseca/v1/api.pb.go @@ -68,7 +68,7 @@ func (x HealthCheckResponse_ServingStatus) Number() protoreflect.EnumNumber { // Deprecated: Use HealthCheckResponse_ServingStatus.Descriptor instead. func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{30, 0} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{36, 0} } type CertificateParameter struct { @@ -392,9 +392,10 @@ type SignedCertificate struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Certificate string `protobuf:"bytes,1,opt,name=certificate,proto3" json:"certificate,omitempty"` - CertificateChain string `protobuf:"bytes,2,opt,name=certificate_chain,json=certificateChain,proto3" json:"certificate_chain,omitempty"` - Metadata *CertificateParameter `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + Certificate string `protobuf:"bytes,1,opt,name=certificate,proto3" json:"certificate,omitempty"` + CertificateChain string `protobuf:"bytes,2,opt,name=certificate_chain,json=certificateChain,proto3" json:"certificate_chain,omitempty"` + Metadata *CertificateParameter `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + IntermediateCertificateChain string `protobuf:"bytes,4,opt,name=intermediate_certificate_chain,json=intermediateCertificateChain,proto3" json:"intermediate_certificate_chain,omitempty"` } func (x *SignedCertificate) Reset() { @@ -450,6 +451,13 @@ func (x *SignedCertificate) GetMetadata() *CertificateParameter { return nil } +func (x *SignedCertificate) GetIntermediateCertificateChain() string { + if x != nil { + return x.IntermediateCertificateChain + } + return "" +} + type CertificateSerialNumber struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -684,7 +692,7 @@ type OperationsSignRequest struct { unknownFields protoimpl.UnknownFields CertificateSigningRequest string `protobuf:"bytes,1,opt,name=certificate_signing_request,json=certificateSigningRequest,proto3" json:"certificate_signing_request,omitempty"` - CertificateAuthority *CertificateAuthorityParameter `protobuf:"bytes,2,opt,name=certificate_authority,json=certificateAuthority,proto3" json:"certificate_authority,omitempty"` + CertificateAuthority *CertificateAuthorityParameter `protobuf:"bytes,2,opt,name=certificate_authority,json=certificateAuthority,proto3,oneof" json:"certificate_authority,omitempty"` ServiceAccount string `protobuf:"bytes,3,opt,name=service_account,json=serviceAccount,proto3" json:"service_account,omitempty"` Environment string `protobuf:"bytes,4,opt,name=environment,proto3" json:"environment,omitempty"` ExtendedKey string `protobuf:"bytes,5,opt,name=extended_key,json=extendedKey,proto3" json:"extended_key,omitempty"` @@ -757,6 +765,132 @@ func (x *OperationsSignRequest) GetExtendedKey() string { return "" } +type Environment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Environment string `protobuf:"bytes,1,opt,name=environment,proto3" json:"environment,omitempty"` +} + +func (x *Environment) Reset() { + *x = Environment{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Environment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Environment) ProtoMessage() {} + +func (x *Environment) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[10] + 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 Environment.ProtoReflect.Descriptor instead. +func (*Environment) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{10} +} + +func (x *Environment) GetEnvironment() string { + if x != nil { + return x.Environment + } + return "" +} + +type QueryCertificateMetadataRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SerialNumber string `protobuf:"bytes,1,opt,name=serial_number,json=serialNumber,proto3" json:"serial_number,omitempty"` + Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"` + Environment string `protobuf:"bytes,3,opt,name=environment,proto3" json:"environment,omitempty"` + ExtendedKey string `protobuf:"bytes,4,opt,name=extended_key,json=extendedKey,proto3" json:"extended_key,omitempty"` + SubjectAlternativeName []string `protobuf:"bytes,5,rep,name=subject_alternative_name,json=subjectAlternativeName,proto3" json:"subject_alternative_name,omitempty"` +} + +func (x *QueryCertificateMetadataRequest) Reset() { + *x = QueryCertificateMetadataRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryCertificateMetadataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryCertificateMetadataRequest) ProtoMessage() {} + +func (x *QueryCertificateMetadataRequest) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[11] + 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 QueryCertificateMetadataRequest.ProtoReflect.Descriptor instead. +func (*QueryCertificateMetadataRequest) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{11} +} + +func (x *QueryCertificateMetadataRequest) GetSerialNumber() string { + if x != nil { + return x.SerialNumber + } + return "" +} + +func (x *QueryCertificateMetadataRequest) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *QueryCertificateMetadataRequest) GetEnvironment() string { + if x != nil { + return x.Environment + } + return "" +} + +func (x *QueryCertificateMetadataRequest) GetExtendedKey() string { + if x != nil { + return x.ExtendedKey + } + return "" +} + +func (x *QueryCertificateMetadataRequest) GetSubjectAlternativeName() []string { + if x != nil { + return x.SubjectAlternativeName + } + return nil +} + type User struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -774,7 +908,7 @@ type User struct { func (x *User) Reset() { *x = User{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[10] + mi := &file_baseca_v1_api_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -787,7 +921,7 @@ func (x *User) String() string { func (*User) ProtoMessage() {} func (x *User) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[10] + mi := &file_baseca_v1_api_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -800,7 +934,7 @@ func (x *User) ProtoReflect() protoreflect.Message { // Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{10} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{12} } func (x *User) GetUuid() string { @@ -863,7 +997,7 @@ type Users struct { func (x *Users) Reset() { *x = Users{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[11] + mi := &file_baseca_v1_api_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -876,7 +1010,7 @@ func (x *Users) String() string { func (*Users) ProtoMessage() {} func (x *Users) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[11] + mi := &file_baseca_v1_api_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -889,7 +1023,7 @@ func (x *Users) ProtoReflect() protoreflect.Message { // Deprecated: Use Users.ProtoReflect.Descriptor instead. func (*Users) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{11} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{13} } func (x *Users) GetUsers() []*User { @@ -911,7 +1045,7 @@ type LoginUserRequest struct { func (x *LoginUserRequest) Reset() { *x = LoginUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[12] + mi := &file_baseca_v1_api_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -924,7 +1058,7 @@ func (x *LoginUserRequest) String() string { func (*LoginUserRequest) ProtoMessage() {} func (x *LoginUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[12] + mi := &file_baseca_v1_api_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -937,7 +1071,7 @@ func (x *LoginUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginUserRequest.ProtoReflect.Descriptor instead. func (*LoginUserRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{12} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{14} } func (x *LoginUserRequest) GetUsername() string { @@ -966,7 +1100,7 @@ type LoginUserResponse struct { func (x *LoginUserResponse) Reset() { *x = LoginUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[13] + mi := &file_baseca_v1_api_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -979,7 +1113,7 @@ func (x *LoginUserResponse) String() string { func (*LoginUserResponse) ProtoMessage() {} func (x *LoginUserResponse) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[13] + mi := &file_baseca_v1_api_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -992,7 +1126,7 @@ func (x *LoginUserResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginUserResponse.ProtoReflect.Descriptor instead. func (*LoginUserResponse) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{13} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{15} } func (x *LoginUserResponse) GetAccessToken() string { @@ -1020,7 +1154,7 @@ type UsernameRequest struct { func (x *UsernameRequest) Reset() { *x = UsernameRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[14] + mi := &file_baseca_v1_api_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1033,7 +1167,7 @@ func (x *UsernameRequest) String() string { func (*UsernameRequest) ProtoMessage() {} func (x *UsernameRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[14] + mi := &file_baseca_v1_api_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1046,7 +1180,7 @@ func (x *UsernameRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UsernameRequest.ProtoReflect.Descriptor instead. func (*UsernameRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{14} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{16} } func (x *UsernameRequest) GetUsername() string { @@ -1068,7 +1202,7 @@ type QueryParameter struct { func (x *QueryParameter) Reset() { *x = QueryParameter{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[15] + mi := &file_baseca_v1_api_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1081,7 +1215,7 @@ func (x *QueryParameter) String() string { func (*QueryParameter) ProtoMessage() {} func (x *QueryParameter) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[15] + mi := &file_baseca_v1_api_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1094,7 +1228,7 @@ func (x *QueryParameter) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryParameter.ProtoReflect.Descriptor instead. func (*QueryParameter) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{15} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{17} } func (x *QueryParameter) GetPageId() int32 { @@ -1126,7 +1260,7 @@ type CreateUserRequest struct { func (x *CreateUserRequest) Reset() { *x = CreateUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[16] + mi := &file_baseca_v1_api_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1139,7 +1273,7 @@ func (x *CreateUserRequest) String() string { func (*CreateUserRequest) ProtoMessage() {} func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[16] + mi := &file_baseca_v1_api_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1152,7 +1286,7 @@ func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateUserRequest.ProtoReflect.Descriptor instead. func (*CreateUserRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{16} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{18} } func (x *CreateUserRequest) GetUsername() string { @@ -1203,7 +1337,7 @@ type UpdateCredentialsRequest struct { func (x *UpdateCredentialsRequest) Reset() { *x = UpdateCredentialsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[17] + mi := &file_baseca_v1_api_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1216,7 +1350,7 @@ func (x *UpdateCredentialsRequest) String() string { func (*UpdateCredentialsRequest) ProtoMessage() {} func (x *UpdateCredentialsRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[17] + mi := &file_baseca_v1_api_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1229,7 +1363,7 @@ func (x *UpdateCredentialsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateCredentialsRequest.ProtoReflect.Descriptor instead. func (*UpdateCredentialsRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{17} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{19} } func (x *UpdateCredentialsRequest) GetUsername() string { @@ -1265,7 +1399,7 @@ type UpdatePermissionsRequest struct { func (x *UpdatePermissionsRequest) Reset() { *x = UpdatePermissionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[18] + mi := &file_baseca_v1_api_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1278,7 +1412,7 @@ func (x *UpdatePermissionsRequest) String() string { func (*UpdatePermissionsRequest) ProtoMessage() {} func (x *UpdatePermissionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[18] + mi := &file_baseca_v1_api_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1291,7 +1425,7 @@ func (x *UpdatePermissionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdatePermissionsRequest.ProtoReflect.Descriptor instead. func (*UpdatePermissionsRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{18} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{20} } func (x *UpdatePermissionsRequest) GetUsername() string { @@ -1329,7 +1463,7 @@ type CreateServiceAccountRequest struct { func (x *CreateServiceAccountRequest) Reset() { *x = CreateServiceAccountRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[19] + mi := &file_baseca_v1_api_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1342,7 +1476,7 @@ func (x *CreateServiceAccountRequest) String() string { func (*CreateServiceAccountRequest) ProtoMessage() {} func (x *CreateServiceAccountRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[19] + mi := &file_baseca_v1_api_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1355,7 +1489,7 @@ func (x *CreateServiceAccountRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateServiceAccountRequest.ProtoReflect.Descriptor instead. func (*CreateServiceAccountRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{19} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{21} } func (x *CreateServiceAccountRequest) GetServiceAccount() string { @@ -1460,7 +1594,7 @@ type CreateServiceAccountResponse struct { func (x *CreateServiceAccountResponse) Reset() { *x = CreateServiceAccountResponse{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[20] + mi := &file_baseca_v1_api_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1473,7 +1607,7 @@ func (x *CreateServiceAccountResponse) String() string { func (*CreateServiceAccountResponse) ProtoMessage() {} func (x *CreateServiceAccountResponse) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[20] + mi := &file_baseca_v1_api_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1486,7 +1620,7 @@ func (x *CreateServiceAccountResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateServiceAccountResponse.ProtoReflect.Descriptor instead. func (*CreateServiceAccountResponse) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{20} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{22} } func (x *CreateServiceAccountResponse) GetClientId() string { @@ -1608,16 +1742,18 @@ type ServiceAccount struct { ExtendedKey string `protobuf:"bytes,7,opt,name=extended_key,json=extendedKey,proto3" json:"extended_key,omitempty"` NodeAttestation *NodeAttestation `protobuf:"bytes,8,opt,name=node_attestation,json=nodeAttestation,proto3" json:"node_attestation,omitempty"` CertificateValidity int32 `protobuf:"varint,9,opt,name=certificate_validity,json=certificateValidity,proto3" json:"certificate_validity,omitempty"` - Team string `protobuf:"bytes,10,opt,name=team,proto3" json:"team,omitempty"` - Email string `protobuf:"bytes,11,opt,name=email,proto3" json:"email,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - CreatedBy string `protobuf:"bytes,13,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` + SubordinateCa string `protobuf:"bytes,10,opt,name=subordinate_ca,json=subordinateCa,proto3" json:"subordinate_ca,omitempty"` + Provisioned bool `protobuf:"varint,11,opt,name=provisioned,proto3" json:"provisioned,omitempty"` + Team string `protobuf:"bytes,12,opt,name=team,proto3" json:"team,omitempty"` + Email string `protobuf:"bytes,13,opt,name=email,proto3" json:"email,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + CreatedBy string `protobuf:"bytes,15,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` } func (x *ServiceAccount) Reset() { *x = ServiceAccount{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[21] + mi := &file_baseca_v1_api_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1630,7 +1766,7 @@ func (x *ServiceAccount) String() string { func (*ServiceAccount) ProtoMessage() {} func (x *ServiceAccount) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[21] + mi := &file_baseca_v1_api_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1643,7 +1779,7 @@ func (x *ServiceAccount) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceAccount.ProtoReflect.Descriptor instead. func (*ServiceAccount) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{21} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{23} } func (x *ServiceAccount) GetClientId() string { @@ -1709,6 +1845,20 @@ func (x *ServiceAccount) GetCertificateValidity() int32 { return 0 } +func (x *ServiceAccount) GetSubordinateCa() string { + if x != nil { + return x.SubordinateCa + } + return "" +} + +func (x *ServiceAccount) GetProvisioned() bool { + if x != nil { + return x.Provisioned + } + return false +} + func (x *ServiceAccount) GetTeam() string { if x != nil { return x.Team @@ -1748,7 +1898,7 @@ type ServiceAccounts struct { func (x *ServiceAccounts) Reset() { *x = ServiceAccounts{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[22] + mi := &file_baseca_v1_api_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1761,7 +1911,7 @@ func (x *ServiceAccounts) String() string { func (*ServiceAccounts) ProtoMessage() {} func (x *ServiceAccounts) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[22] + mi := &file_baseca_v1_api_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1774,7 +1924,7 @@ func (x *ServiceAccounts) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceAccounts.ProtoReflect.Descriptor instead. func (*ServiceAccounts) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{22} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{24} } func (x *ServiceAccounts) GetServiceAccounts() []*ServiceAccount { @@ -1784,31 +1934,39 @@ func (x *ServiceAccounts) GetServiceAccounts() []*ServiceAccount { return nil } -type NodeAttestation struct { +type CreateProvisionerAccountRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AwsIid *AWSInstanceIdentityDocument `protobuf:"bytes,1,opt,name=aws_iid,json=awsIid,proto3" json:"aws_iid,omitempty"` + ProvisionerAccount string `protobuf:"bytes,1,opt,name=provisioner_account,json=provisionerAccount,proto3" json:"provisioner_account,omitempty"` + Environments []string `protobuf:"bytes,2,rep,name=environments,proto3" json:"environments,omitempty"` + RegularExpression string `protobuf:"bytes,3,opt,name=regular_expression,json=regularExpression,proto3" json:"regular_expression,omitempty"` + SubjectAlternativeNames []string `protobuf:"bytes,4,rep,name=subject_alternative_names,json=subjectAlternativeNames,proto3" json:"subject_alternative_names,omitempty"` + ExtendedKeys []string `protobuf:"bytes,5,rep,name=extended_keys,json=extendedKeys,proto3" json:"extended_keys,omitempty"` + MaxCertificateValidity uint32 `protobuf:"varint,6,opt,name=max_certificate_validity,json=maxCertificateValidity,proto3" json:"max_certificate_validity,omitempty"` + NodeAttestation *NodeAttestation `protobuf:"bytes,7,opt,name=node_attestation,json=nodeAttestation,proto3,oneof" json:"node_attestation,omitempty"` + Team string `protobuf:"bytes,8,opt,name=team,proto3" json:"team,omitempty"` + Email string `protobuf:"bytes,9,opt,name=email,proto3" json:"email,omitempty"` } -func (x *NodeAttestation) Reset() { - *x = NodeAttestation{} +func (x *CreateProvisionerAccountRequest) Reset() { + *x = CreateProvisionerAccountRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[23] + mi := &file_baseca_v1_api_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *NodeAttestation) String() string { +func (x *CreateProvisionerAccountRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NodeAttestation) ProtoMessage() {} +func (*CreateProvisionerAccountRequest) ProtoMessage() {} -func (x *NodeAttestation) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[23] +func (x *CreateProvisionerAccountRequest) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1819,49 +1977,477 @@ func (x *NodeAttestation) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NodeAttestation.ProtoReflect.Descriptor instead. -func (*NodeAttestation) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{23} +// Deprecated: Use CreateProvisionerAccountRequest.ProtoReflect.Descriptor instead. +func (*CreateProvisionerAccountRequest) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{25} } -func (x *NodeAttestation) GetAwsIid() *AWSInstanceIdentityDocument { +func (x *CreateProvisionerAccountRequest) GetProvisionerAccount() string { if x != nil { - return x.AwsIid + return x.ProvisionerAccount + } + return "" +} + +func (x *CreateProvisionerAccountRequest) GetEnvironments() []string { + if x != nil { + return x.Environments } return nil } -type AWSInstanceIdentityDocument struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields +func (x *CreateProvisionerAccountRequest) GetRegularExpression() string { + if x != nil { + return x.RegularExpression + } + return "" +} - RoleArn string `protobuf:"bytes,1,opt,name=role_arn,json=roleArn,proto3" json:"role_arn,omitempty"` - AssumeRole string `protobuf:"bytes,2,opt,name=assume_role,json=assumeRole,proto3" json:"assume_role,omitempty"` - SecurityGroups []string `protobuf:"bytes,3,rep,name=security_groups,json=securityGroups,proto3" json:"security_groups,omitempty"` - Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` - InstanceId string `protobuf:"bytes,5,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` - ImageId string `protobuf:"bytes,6,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` - InstanceTags map[string]string `protobuf:"bytes,7,rep,name=instance_tags,json=instanceTags,proto3" json:"instance_tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +func (x *CreateProvisionerAccountRequest) GetSubjectAlternativeNames() []string { + if x != nil { + return x.SubjectAlternativeNames + } + return nil } -func (x *AWSInstanceIdentityDocument) Reset() { - *x = AWSInstanceIdentityDocument{} - if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *CreateProvisionerAccountRequest) GetExtendedKeys() []string { + if x != nil { + return x.ExtendedKeys } + return nil } -func (x *AWSInstanceIdentityDocument) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *CreateProvisionerAccountRequest) GetMaxCertificateValidity() uint32 { + if x != nil { + return x.MaxCertificateValidity + } + return 0 +} + +func (x *CreateProvisionerAccountRequest) GetNodeAttestation() *NodeAttestation { + if x != nil { + return x.NodeAttestation + } + return nil +} + +func (x *CreateProvisionerAccountRequest) GetTeam() string { + if x != nil { + return x.Team + } + return "" +} + +func (x *CreateProvisionerAccountRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type CreateProvisionerAccountResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientToken string `protobuf:"bytes,2,opt,name=client_token,json=clientToken,proto3" json:"client_token,omitempty"` + ProvisionerAccount string `protobuf:"bytes,3,opt,name=provisioner_account,json=provisionerAccount,proto3" json:"provisioner_account,omitempty"` + Environments []string `protobuf:"bytes,4,rep,name=environments,proto3" json:"environments,omitempty"` + RegularExpression string `protobuf:"bytes,5,opt,name=regular_expression,json=regularExpression,proto3" json:"regular_expression,omitempty"` + SubjectAlternativeNames []string `protobuf:"bytes,6,rep,name=subject_alternative_names,json=subjectAlternativeNames,proto3" json:"subject_alternative_names,omitempty"` + ExtendedKeys []string `protobuf:"bytes,8,rep,name=extended_keys,json=extendedKeys,proto3" json:"extended_keys,omitempty"` + NodeAttestation *NodeAttestation `protobuf:"bytes,9,opt,name=node_attestation,json=nodeAttestation,proto3" json:"node_attestation,omitempty"` + MaxCertificateValidity uint32 `protobuf:"varint,10,opt,name=max_certificate_validity,json=maxCertificateValidity,proto3" json:"max_certificate_validity,omitempty"` + Team string `protobuf:"bytes,11,opt,name=team,proto3" json:"team,omitempty"` + Email string `protobuf:"bytes,12,opt,name=email,proto3" json:"email,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + CreatedBy string `protobuf:"bytes,14,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` +} + +func (x *CreateProvisionerAccountResponse) Reset() { + *x = CreateProvisionerAccountResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateProvisionerAccountResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateProvisionerAccountResponse) ProtoMessage() {} + +func (x *CreateProvisionerAccountResponse) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[26] + 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 CreateProvisionerAccountResponse.ProtoReflect.Descriptor instead. +func (*CreateProvisionerAccountResponse) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{26} +} + +func (x *CreateProvisionerAccountResponse) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *CreateProvisionerAccountResponse) GetClientToken() string { + if x != nil { + return x.ClientToken + } + return "" +} + +func (x *CreateProvisionerAccountResponse) GetProvisionerAccount() string { + if x != nil { + return x.ProvisionerAccount + } + return "" +} + +func (x *CreateProvisionerAccountResponse) GetEnvironments() []string { + if x != nil { + return x.Environments + } + return nil +} + +func (x *CreateProvisionerAccountResponse) GetRegularExpression() string { + if x != nil { + return x.RegularExpression + } + return "" +} + +func (x *CreateProvisionerAccountResponse) GetSubjectAlternativeNames() []string { + if x != nil { + return x.SubjectAlternativeNames + } + return nil +} + +func (x *CreateProvisionerAccountResponse) GetExtendedKeys() []string { + if x != nil { + return x.ExtendedKeys + } + return nil +} + +func (x *CreateProvisionerAccountResponse) GetNodeAttestation() *NodeAttestation { + if x != nil { + return x.NodeAttestation + } + return nil +} + +func (x *CreateProvisionerAccountResponse) GetMaxCertificateValidity() uint32 { + if x != nil { + return x.MaxCertificateValidity + } + return 0 +} + +func (x *CreateProvisionerAccountResponse) GetTeam() string { + if x != nil { + return x.Team + } + return "" +} + +func (x *CreateProvisionerAccountResponse) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *CreateProvisionerAccountResponse) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *CreateProvisionerAccountResponse) GetCreatedBy() string { + if x != nil { + return x.CreatedBy + } + return "" +} + +type ProvisionerAccounts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProvisionerAccounts []*ProvisionerAccount `protobuf:"bytes,1,rep,name=provisioner_accounts,json=provisionerAccounts,proto3" json:"provisioner_accounts,omitempty"` +} + +func (x *ProvisionerAccounts) Reset() { + *x = ProvisionerAccounts{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProvisionerAccounts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProvisionerAccounts) ProtoMessage() {} + +func (x *ProvisionerAccounts) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[27] + 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 ProvisionerAccounts.ProtoReflect.Descriptor instead. +func (*ProvisionerAccounts) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{27} +} + +func (x *ProvisionerAccounts) GetProvisionerAccounts() []*ProvisionerAccount { + if x != nil { + return x.ProvisionerAccounts + } + return nil +} + +type ProvisionerAccount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ProvisionerAccount string `protobuf:"bytes,2,opt,name=provisioner_account,json=provisionerAccount,proto3" json:"provisioner_account,omitempty"` + Environments []string `protobuf:"bytes,3,rep,name=environments,proto3" json:"environments,omitempty"` + RegularExpression string `protobuf:"bytes,4,opt,name=regular_expression,json=regularExpression,proto3" json:"regular_expression,omitempty"` + SubjectAlternativeNames []string `protobuf:"bytes,5,rep,name=subject_alternative_names,json=subjectAlternativeNames,proto3" json:"subject_alternative_names,omitempty"` + ExtendedKeys []string `protobuf:"bytes,7,rep,name=extended_keys,json=extendedKeys,proto3" json:"extended_keys,omitempty"` + NodeAttestation *NodeAttestation `protobuf:"bytes,8,opt,name=node_attestation,json=nodeAttestation,proto3" json:"node_attestation,omitempty"` + MaxCertificateValidity uint32 `protobuf:"varint,9,opt,name=max_certificate_validity,json=maxCertificateValidity,proto3" json:"max_certificate_validity,omitempty"` + Team string `protobuf:"bytes,10,opt,name=team,proto3" json:"team,omitempty"` + Email string `protobuf:"bytes,11,opt,name=email,proto3" json:"email,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + CreatedBy string `protobuf:"bytes,13,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` +} + +func (x *ProvisionerAccount) Reset() { + *x = ProvisionerAccount{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProvisionerAccount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProvisionerAccount) ProtoMessage() {} + +func (x *ProvisionerAccount) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[28] + 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 ProvisionerAccount.ProtoReflect.Descriptor instead. +func (*ProvisionerAccount) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{28} +} + +func (x *ProvisionerAccount) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *ProvisionerAccount) GetProvisionerAccount() string { + if x != nil { + return x.ProvisionerAccount + } + return "" +} + +func (x *ProvisionerAccount) GetEnvironments() []string { + if x != nil { + return x.Environments + } + return nil +} + +func (x *ProvisionerAccount) GetRegularExpression() string { + if x != nil { + return x.RegularExpression + } + return "" +} + +func (x *ProvisionerAccount) GetSubjectAlternativeNames() []string { + if x != nil { + return x.SubjectAlternativeNames + } + return nil +} + +func (x *ProvisionerAccount) GetExtendedKeys() []string { + if x != nil { + return x.ExtendedKeys + } + return nil +} + +func (x *ProvisionerAccount) GetNodeAttestation() *NodeAttestation { + if x != nil { + return x.NodeAttestation + } + return nil +} + +func (x *ProvisionerAccount) GetMaxCertificateValidity() uint32 { + if x != nil { + return x.MaxCertificateValidity + } + return 0 +} + +func (x *ProvisionerAccount) GetTeam() string { + if x != nil { + return x.Team + } + return "" +} + +func (x *ProvisionerAccount) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *ProvisionerAccount) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *ProvisionerAccount) GetCreatedBy() string { + if x != nil { + return x.CreatedBy + } + return "" +} + +type NodeAttestation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AwsIid *AWSInstanceIdentityDocument `protobuf:"bytes,1,opt,name=aws_iid,json=awsIid,proto3" json:"aws_iid,omitempty"` +} + +func (x *NodeAttestation) Reset() { + *x = NodeAttestation{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeAttestation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeAttestation) ProtoMessage() {} + +func (x *NodeAttestation) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[29] + 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 NodeAttestation.ProtoReflect.Descriptor instead. +func (*NodeAttestation) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{29} +} + +func (x *NodeAttestation) GetAwsIid() *AWSInstanceIdentityDocument { + if x != nil { + return x.AwsIid + } + return nil +} + +type AWSInstanceIdentityDocument struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoleArn string `protobuf:"bytes,1,opt,name=role_arn,json=roleArn,proto3" json:"role_arn,omitempty"` + AssumeRole string `protobuf:"bytes,2,opt,name=assume_role,json=assumeRole,proto3" json:"assume_role,omitempty"` + SecurityGroups []string `protobuf:"bytes,3,rep,name=security_groups,json=securityGroups,proto3" json:"security_groups,omitempty"` + Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` + InstanceId string `protobuf:"bytes,5,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + ImageId string `protobuf:"bytes,6,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"` + InstanceTags map[string]string `protobuf:"bytes,7,rep,name=instance_tags,json=instanceTags,proto3" json:"instance_tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *AWSInstanceIdentityDocument) Reset() { + *x = AWSInstanceIdentityDocument{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AWSInstanceIdentityDocument) String() string { + return protoimpl.X.MessageStringOf(x) } func (*AWSInstanceIdentityDocument) ProtoMessage() {} func (x *AWSInstanceIdentityDocument) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[24] + mi := &file_baseca_v1_api_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1874,7 +2460,7 @@ func (x *AWSInstanceIdentityDocument) ProtoReflect() protoreflect.Message { // Deprecated: Use AWSInstanceIdentityDocument.ProtoReflect.Descriptor instead. func (*AWSInstanceIdentityDocument) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{24} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{30} } func (x *AWSInstanceIdentityDocument) GetRoleArn() string { @@ -1926,7 +2512,7 @@ func (x *AWSInstanceIdentityDocument) GetInstanceTags() map[string]string { return nil } -type ServiceAccountId struct { +type AccountId struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1934,23 +2520,23 @@ type ServiceAccountId struct { Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` } -func (x *ServiceAccountId) Reset() { - *x = ServiceAccountId{} +func (x *AccountId) Reset() { + *x = AccountId{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[25] + mi := &file_baseca_v1_api_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *ServiceAccountId) String() string { +func (x *AccountId) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ServiceAccountId) ProtoMessage() {} +func (*AccountId) ProtoMessage() {} -func (x *ServiceAccountId) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[25] +func (x *AccountId) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1961,43 +2547,247 @@ func (x *ServiceAccountId) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ServiceAccountId.ProtoReflect.Descriptor instead. -func (*ServiceAccountId) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{25} +// Deprecated: Use AccountId.ProtoReflect.Descriptor instead. +func (*AccountId) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{31} } -func (x *ServiceAccountId) GetUuid() string { +func (x *AccountId) GetUuid() string { if x != nil { return x.Uuid } return "" } -type ServiceAccountName struct { +type GetServiceAccountMetadataRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields ServiceAccount string `protobuf:"bytes,1,opt,name=service_account,json=serviceAccount,proto3" json:"service_account,omitempty"` + Environment string `protobuf:"bytes,2,opt,name=environment,proto3" json:"environment,omitempty"` + ExtendedKey string `protobuf:"bytes,3,opt,name=extended_key,json=extendedKey,proto3" json:"extended_key,omitempty"` +} + +func (x *GetServiceAccountMetadataRequest) Reset() { + *x = GetServiceAccountMetadataRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetServiceAccountMetadataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetServiceAccountMetadataRequest) ProtoMessage() {} + +func (x *GetServiceAccountMetadataRequest) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[32] + 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 GetServiceAccountMetadataRequest.ProtoReflect.Descriptor instead. +func (*GetServiceAccountMetadataRequest) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{32} +} + +func (x *GetServiceAccountMetadataRequest) GetServiceAccount() string { + if x != nil { + return x.ServiceAccount + } + return "" +} + +func (x *GetServiceAccountMetadataRequest) GetEnvironment() string { + if x != nil { + return x.Environment + } + return "" +} + +func (x *GetServiceAccountMetadataRequest) GetExtendedKey() string { + if x != nil { + return x.ExtendedKey + } + return "" +} + +type ProvisionServiceAccountRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServiceAccount string `protobuf:"bytes,1,opt,name=service_account,json=serviceAccount,proto3" json:"service_account,omitempty"` + Environment string `protobuf:"bytes,2,opt,name=environment,proto3" json:"environment,omitempty"` + RegularExpression string `protobuf:"bytes,3,opt,name=regular_expression,json=regularExpression,proto3" json:"regular_expression,omitempty"` + SubjectAlternativeNames []string `protobuf:"bytes,4,rep,name=subject_alternative_names,json=subjectAlternativeNames,proto3" json:"subject_alternative_names,omitempty"` + CertificateAuthorities []string `protobuf:"bytes,5,rep,name=certificate_authorities,json=certificateAuthorities,proto3" json:"certificate_authorities,omitempty"` + ExtendedKey string `protobuf:"bytes,6,opt,name=extended_key,json=extendedKey,proto3" json:"extended_key,omitempty"` + CertificateValidity int32 `protobuf:"varint,7,opt,name=certificate_validity,json=certificateValidity,proto3" json:"certificate_validity,omitempty"` + SubordinateCa string `protobuf:"bytes,8,opt,name=subordinate_ca,json=subordinateCa,proto3" json:"subordinate_ca,omitempty"` + NodeAttestation *NodeAttestation `protobuf:"bytes,9,opt,name=node_attestation,json=nodeAttestation,proto3" json:"node_attestation,omitempty"` + Team string `protobuf:"bytes,10,opt,name=team,proto3" json:"team,omitempty"` + Email string `protobuf:"bytes,11,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *ProvisionServiceAccountRequest) Reset() { + *x = ProvisionServiceAccountRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_baseca_v1_api_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProvisionServiceAccountRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProvisionServiceAccountRequest) ProtoMessage() {} + +func (x *ProvisionServiceAccountRequest) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[33] + 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 ProvisionServiceAccountRequest.ProtoReflect.Descriptor instead. +func (*ProvisionServiceAccountRequest) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{33} +} + +func (x *ProvisionServiceAccountRequest) GetServiceAccount() string { + if x != nil { + return x.ServiceAccount + } + return "" +} + +func (x *ProvisionServiceAccountRequest) GetEnvironment() string { + if x != nil { + return x.Environment + } + return "" +} + +func (x *ProvisionServiceAccountRequest) GetRegularExpression() string { + if x != nil { + return x.RegularExpression + } + return "" +} + +func (x *ProvisionServiceAccountRequest) GetSubjectAlternativeNames() []string { + if x != nil { + return x.SubjectAlternativeNames + } + return nil +} + +func (x *ProvisionServiceAccountRequest) GetCertificateAuthorities() []string { + if x != nil { + return x.CertificateAuthorities + } + return nil +} + +func (x *ProvisionServiceAccountRequest) GetExtendedKey() string { + if x != nil { + return x.ExtendedKey + } + return "" +} + +func (x *ProvisionServiceAccountRequest) GetCertificateValidity() int32 { + if x != nil { + return x.CertificateValidity + } + return 0 +} + +func (x *ProvisionServiceAccountRequest) GetSubordinateCa() string { + if x != nil { + return x.SubordinateCa + } + return "" +} + +func (x *ProvisionServiceAccountRequest) GetNodeAttestation() *NodeAttestation { + if x != nil { + return x.NodeAttestation + } + return nil +} + +func (x *ProvisionServiceAccountRequest) GetTeam() string { + if x != nil { + return x.Team + } + return "" +} + +func (x *ProvisionServiceAccountRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type ProvisionServiceAccountResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientToken string `protobuf:"bytes,2,opt,name=client_token,json=clientToken,proto3" json:"client_token,omitempty"` + ServiceAccount string `protobuf:"bytes,3,opt,name=service_account,json=serviceAccount,proto3" json:"service_account,omitempty"` + Environment string `protobuf:"bytes,4,opt,name=environment,proto3" json:"environment,omitempty"` + RegularExpression string `protobuf:"bytes,5,opt,name=regular_expression,json=regularExpression,proto3" json:"regular_expression,omitempty"` + SubjectAlternativeNames []string `protobuf:"bytes,6,rep,name=subject_alternative_names,json=subjectAlternativeNames,proto3" json:"subject_alternative_names,omitempty"` + CertificateAuthorities []string `protobuf:"bytes,7,rep,name=certificate_authorities,json=certificateAuthorities,proto3" json:"certificate_authorities,omitempty"` + ExtendedKey string `protobuf:"bytes,8,opt,name=extended_key,json=extendedKey,proto3" json:"extended_key,omitempty"` + NodeAttestation *NodeAttestation `protobuf:"bytes,9,opt,name=node_attestation,json=nodeAttestation,proto3" json:"node_attestation,omitempty"` + CertificateValidity int32 `protobuf:"varint,10,opt,name=certificate_validity,json=certificateValidity,proto3" json:"certificate_validity,omitempty"` + SubordinateCa string `protobuf:"bytes,11,opt,name=subordinate_ca,json=subordinateCa,proto3" json:"subordinate_ca,omitempty"` + Team string `protobuf:"bytes,12,opt,name=team,proto3" json:"team,omitempty"` + Email string `protobuf:"bytes,13,opt,name=email,proto3" json:"email,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + CreatedBy string `protobuf:"bytes,15,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` } -func (x *ServiceAccountName) Reset() { - *x = ServiceAccountName{} +func (x *ProvisionServiceAccountResponse) Reset() { + *x = ProvisionServiceAccountResponse{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[26] + mi := &file_baseca_v1_api_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *ServiceAccountName) String() string { +func (x *ProvisionServiceAccountResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ServiceAccountName) ProtoMessage() {} +func (*ProvisionServiceAccountResponse) ProtoMessage() {} -func (x *ServiceAccountName) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[26] +func (x *ProvisionServiceAccountResponse) ProtoReflect() protoreflect.Message { + mi := &file_baseca_v1_api_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2008,112 +2798,116 @@ func (x *ServiceAccountName) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ServiceAccountName.ProtoReflect.Descriptor instead. -func (*ServiceAccountName) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{26} +// Deprecated: Use ProvisionServiceAccountResponse.ProtoReflect.Descriptor instead. +func (*ProvisionServiceAccountResponse) Descriptor() ([]byte, []int) { + return file_baseca_v1_api_proto_rawDescGZIP(), []int{34} } -func (x *ServiceAccountName) GetServiceAccount() string { +func (x *ProvisionServiceAccountResponse) GetClientId() string { if x != nil { - return x.ServiceAccount + return x.ClientId } return "" } -type ProvisionServiceAccountRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Account *CreateServiceAccountRequest `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` +func (x *ProvisionServiceAccountResponse) GetClientToken() string { + if x != nil { + return x.ClientToken + } + return "" } -func (x *ProvisionServiceAccountRequest) Reset() { - *x = ProvisionServiceAccountRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *ProvisionServiceAccountResponse) GetServiceAccount() string { + if x != nil { + return x.ServiceAccount } + return "" } -func (x *ProvisionServiceAccountRequest) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *ProvisionServiceAccountResponse) GetEnvironment() string { + if x != nil { + return x.Environment + } + return "" } -func (*ProvisionServiceAccountRequest) ProtoMessage() {} - -func (x *ProvisionServiceAccountRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms +func (x *ProvisionServiceAccountResponse) GetRegularExpression() string { + if x != nil { + return x.RegularExpression } - return mi.MessageOf(x) + return "" } -// Deprecated: Use ProvisionServiceAccountRequest.ProtoReflect.Descriptor instead. -func (*ProvisionServiceAccountRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{27} +func (x *ProvisionServiceAccountResponse) GetSubjectAlternativeNames() []string { + if x != nil { + return x.SubjectAlternativeNames + } + return nil } -func (x *ProvisionServiceAccountRequest) GetAccount() *CreateServiceAccountRequest { +func (x *ProvisionServiceAccountResponse) GetCertificateAuthorities() []string { if x != nil { - return x.Account + return x.CertificateAuthorities } return nil } -type ProvisionServiceAccountResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Account *CreateServiceAccountResponse `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` +func (x *ProvisionServiceAccountResponse) GetExtendedKey() string { + if x != nil { + return x.ExtendedKey + } + return "" } -func (x *ProvisionServiceAccountResponse) Reset() { - *x = ProvisionServiceAccountResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *ProvisionServiceAccountResponse) GetNodeAttestation() *NodeAttestation { + if x != nil { + return x.NodeAttestation } + return nil } -func (x *ProvisionServiceAccountResponse) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *ProvisionServiceAccountResponse) GetCertificateValidity() int32 { + if x != nil { + return x.CertificateValidity + } + return 0 } -func (*ProvisionServiceAccountResponse) ProtoMessage() {} +func (x *ProvisionServiceAccountResponse) GetSubordinateCa() string { + if x != nil { + return x.SubordinateCa + } + return "" +} -func (x *ProvisionServiceAccountResponse) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms +func (x *ProvisionServiceAccountResponse) GetTeam() string { + if x != nil { + return x.Team } - return mi.MessageOf(x) + return "" } -// Deprecated: Use ProvisionServiceAccountResponse.ProtoReflect.Descriptor instead. -func (*ProvisionServiceAccountResponse) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{28} +func (x *ProvisionServiceAccountResponse) GetEmail() string { + if x != nil { + return x.Email + } + return "" } -func (x *ProvisionServiceAccountResponse) GetAccount() *CreateServiceAccountResponse { +func (x *ProvisionServiceAccountResponse) GetCreatedAt() *timestamppb.Timestamp { if x != nil { - return x.Account + return x.CreatedAt } return nil } +func (x *ProvisionServiceAccountResponse) GetCreatedBy() string { + if x != nil { + return x.CreatedBy + } + return "" +} + type HealthCheckRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2125,7 +2919,7 @@ type HealthCheckRequest struct { func (x *HealthCheckRequest) Reset() { *x = HealthCheckRequest{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[29] + mi := &file_baseca_v1_api_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2138,7 +2932,7 @@ func (x *HealthCheckRequest) String() string { func (*HealthCheckRequest) ProtoMessage() {} func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[29] + mi := &file_baseca_v1_api_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2151,7 +2945,7 @@ func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{29} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{35} } func (x *HealthCheckRequest) GetService() string { @@ -2172,7 +2966,7 @@ type HealthCheckResponse struct { func (x *HealthCheckResponse) Reset() { *x = HealthCheckResponse{} if protoimpl.UnsafeEnabled { - mi := &file_baseca_v1_api_proto_msgTypes[30] + mi := &file_baseca_v1_api_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2185,7 +2979,7 @@ func (x *HealthCheckResponse) String() string { func (*HealthCheckResponse) ProtoMessage() {} func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_baseca_v1_api_proto_msgTypes[30] + mi := &file_baseca_v1_api_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2198,7 +2992,7 @@ func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_baseca_v1_api_proto_rawDescGZIP(), []int{30} + return file_baseca_v1_api_proto_rawDescGZIP(), []int{36} } func (x *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus { @@ -2276,7 +3070,7 @@ var file_baseca_v1_api_proto_rawDesc = []byte{ 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x11, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe5, 0x01, 0x0a, 0x11, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, @@ -2286,396 +3080,630 @@ var file_baseca_v1_api_proto_rawDesc = []byte{ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x17, 0x43, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x70, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x6c, 0x0a, 0x18, 0x52, 0x65, 0x76, - 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, - 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x9d, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x76, 0x6f, - 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x0f, 0x72, 0x65, - 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x1e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x1c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x3e, 0x0a, + 0x17, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x70, 0x0a, + 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, + 0x6c, 0x0a, 0x18, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x76, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x9d, 0x01, + 0x0a, 0x19, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x43, 0x0a, 0x0f, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc3, 0x02, + 0x0a, 0x15, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x69, 0x67, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x1b, 0x63, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x62, 0x0a, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x48, 0x00, 0x52, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, + 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x22, 0x2f, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x22, 0xdf, 0x01, 0x0a, 0x1f, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x18, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x96, 0x02, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, + 0x75, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4e, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x0e, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xa4, 0x02, 0x0a, 0x15, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x3e, 0x0a, 0x1b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x5d, 0x0a, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x28, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, - 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x14, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x65, - 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0x96, - 0x02, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4e, 0x0a, 0x15, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2e, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x12, 0x25, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x22, 0x5b, 0x0a, 0x11, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x04, 0x75, - 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, - 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, - 0x22, 0x2d, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x13, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, + 0x2e, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, + 0x4a, 0x0a, 0x10, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, - 0x46, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x70, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7d, 0x0a, 0x18, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x29, - 0x0a, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x58, 0x0a, 0x18, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x5b, 0x0a, 0x11, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2d, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x46, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, + 0xa0, 0x01, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0xb0, 0x04, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, - 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x32, - 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, - 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x88, - 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, - 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, - 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, - 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, - 0x0e, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x74, 0x65, 0x43, 0x61, 0x12, 0x4a, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x0f, 0x6e, 0x6f, - 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x72, - 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x95, 0x05, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, - 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, - 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, - 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, - 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x10, 0x6e, 0x6f, 0x64, - 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, - 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x74, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, - 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x43, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, - 0x61, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0xbd, - 0x04, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x27, - 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, - 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, - 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x67, - 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x7d, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x22, 0x58, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb0, 0x04, 0x0a, 0x1b, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, + 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, + 0x65, 0x79, 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, + 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x43, 0x61, 0x12, 0x4a, 0x0a, 0x10, + 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, + 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x01, 0x52, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x6e, 0x6f, + 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x95, + 0x05, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, + 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, + 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, + 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, + 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, + 0x79, 0x12, 0x45, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, + 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x73, + 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, + 0x43, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x86, 0x05, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, + 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x17, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, + 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, + 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4e, + 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, + 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x31, 0x0a, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, + 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, + 0x65, 0x5f, 0x63, 0x61, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x6f, + 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x43, 0x61, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x65, 0x61, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, + 0x57, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x12, 0x44, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0xcb, 0x03, 0x0a, 0x1f, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x13, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, + 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, + 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, + 0x73, 0x12, 0x38, 0x0a, 0x18, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x16, 0x6d, 0x61, 0x78, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x4a, 0x0a, 0x10, 0x6e, + 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, + 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xcc, 0x04, 0x0a, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2f, 0x0a, 0x13, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, + 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, + 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x45, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, - 0x61, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x57, - 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x73, 0x12, 0x44, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x62, 0x61, - 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0x52, 0x0a, 0x0f, 0x4e, 0x6f, 0x64, 0x65, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x07, 0x61, 0x77, - 0x73, 0x5f, 0x69, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x62, 0x61, - 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x77, 0x73, 0x49, 0x69, 0x64, 0x22, 0xf6, 0x02, 0x0a, 0x1b, - 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, - 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, - 0x6f, 0x6c, 0x65, 0x41, 0x72, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, - 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x73, 0x73, - 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, - 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x49, 0x64, 0x12, 0x5d, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x62, 0x61, - 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, - 0x61, 0x67, 0x73, 0x1a, 0x3f, 0x0a, 0x11, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, - 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x3d, 0x0a, 0x12, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x62, 0x0a, 0x1e, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, - 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, - 0x64, 0x0a, 0x1f, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x41, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, - 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x3a, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, - 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x32, - 0xc2, 0x03, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, - 0x4d, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x43, 0x53, 0x52, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x73, - 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x55, - 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x22, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x62, 0x61, 0x73, 0x65, - 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x18, 0x6d, 0x61, 0x78, 0x5f, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x69, 0x74, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x16, 0x6d, 0x61, 0x78, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, + 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x67, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x14, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x61, 0x73, + 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0x9b, + 0x04, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, + 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x67, 0x75, 0x6c, + 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, 0x78, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, + 0x65, 0x79, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x45, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x5f, + 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x6e, + 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, + 0x0a, 0x18, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x16, 0x6d, 0x61, 0x78, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x52, 0x0a, 0x0f, + 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x3f, 0x0a, 0x07, 0x61, 0x77, 0x73, 0x5f, 0x69, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x77, 0x73, 0x49, 0x69, 0x64, + 0x22, 0xf6, 0x02, 0x0a, 0x1b, 0x41, 0x57, 0x53, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x41, 0x72, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, + 0x73, 0x73, 0x75, 0x6d, 0x65, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, + 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x5d, 0x0a, 0x0d, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x38, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x1a, 0x3f, 0x0a, 0x11, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1f, 0x0a, 0x09, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x90, 0x01, 0x0a, 0x20, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, 0x69, + 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xfd, 0x03, + 0x0a, 0x1e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, + 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x73, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4b, + 0x65, 0x79, 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, + 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x43, 0x61, 0x12, 0x45, 0x0a, 0x10, + 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, + 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x98, 0x05, + 0x0a, 0x1f, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, + 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x12, + 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, + 0x72, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x73, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, + 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, + 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x10, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x14, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69, + 0x74, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, + 0x0e, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, + 0x74, 0x65, 0x43, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x2e, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x2c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, + 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, + 0x10, 0x02, 0x32, 0xac, 0x04, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x12, 0x4d, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x43, 0x53, 0x52, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, - 0x5e, 0x0a, 0x11, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x62, 0x61, 0x73, 0x65, - 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x53, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x69, 0x67, - 0x6e, 0x43, 0x53, 0x52, 0x12, 0x20, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, - 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x32, 0xe0, 0x03, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x46, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1b, 0x2e, - 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x61, 0x73, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x12, 0x55, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x12, 0x5e, 0x0a, 0x11, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x53, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x53, 0x69, 0x67, 0x6e, 0x43, 0x53, 0x52, 0x12, 0x20, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x69, + 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x61, 0x73, 0x65, + 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x18, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x2a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x32, 0xe0, 0x03, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x46, 0x0a, + 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x36, 0x0a, 0x07, 0x47, 0x65, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x12, 0x38, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, - 0x19, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x1a, 0x10, 0x2e, 0x62, 0x61, 0x73, - 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x3b, 0x0a, 0x0a, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x62, 0x61, 0x73, - 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, - 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x15, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x12, 0x23, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, - 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x23, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x32, 0xa4, 0x04, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x67, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x2e, 0x62, 0x61, - 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x17, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x36, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, + 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x38, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x19, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x1a, 0x10, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, + 0x23, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, + 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x32, 0xd8, 0x07, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x67, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x26, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, + 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x27, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, 0x18, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2b, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, - 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x19, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x1a, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x4f, 0x0a, 0x15, + 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x1a, 0x1d, 0x2e, + 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x44, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x55, 0x75, 0x69, 0x64, 0x12, 0x1b, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x49, 0x64, 0x1a, 0x19, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x52, 0x0a, - 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x1a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x73, 0x12, 0x4b, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x62, 0x61, 0x73, 0x65, - 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, + 0x74, 0x12, 0x14, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x1a, 0x19, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x64, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x2b, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x62, + 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x14, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0x50, - 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x46, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x12, 0x1d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, - 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1e, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, - 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2f, 0x76, 0x31, 0x3b, - 0x61, 0x70, 0x69, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4f, + 0x0a, 0x1f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x14, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x48, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x62, 0x61, + 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, + 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x70, 0x0a, 0x17, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x13, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x12, 0x19, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x1a, 0x1a, 0x2e, + 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x54, 0x0a, 0x17, 0x4c, 0x69, 0x73, + 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x73, 0x12, 0x19, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x1a, + 0x1e, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x32, + 0x50, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x46, 0x0a, 0x05, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x12, 0x1d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1e, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x63, 0x61, 0x2f, 0x76, 0x31, + 0x3b, 0x61, 0x70, 0x69, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2691,110 +3719,135 @@ func file_baseca_v1_api_proto_rawDescGZIP() []byte { } var file_baseca_v1_api_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_baseca_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 32) +var file_baseca_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 38) var file_baseca_v1_api_proto_goTypes = []interface{}{ - (HealthCheckResponse_ServingStatus)(0), // 0: baseca.v1.HealthCheckResponse.ServingStatus - (*CertificateParameter)(nil), // 1: baseca.v1.CertificateParameter - (*CertificatesParameter)(nil), // 2: baseca.v1.CertificatesParameter - (*CertificateAuthorityParameter)(nil), // 3: baseca.v1.CertificateAuthorityParameter - (*CertificateSigningRequest)(nil), // 4: baseca.v1.CertificateSigningRequest - (*SignedCertificate)(nil), // 5: baseca.v1.SignedCertificate - (*CertificateSerialNumber)(nil), // 6: baseca.v1.CertificateSerialNumber - (*ListCertificatesRequest)(nil), // 7: baseca.v1.ListCertificatesRequest - (*RevokeCertificateRequest)(nil), // 8: baseca.v1.RevokeCertificateRequest - (*RevokeCertificateResponse)(nil), // 9: baseca.v1.RevokeCertificateResponse - (*OperationsSignRequest)(nil), // 10: baseca.v1.OperationsSignRequest - (*User)(nil), // 11: baseca.v1.User - (*Users)(nil), // 12: baseca.v1.Users - (*LoginUserRequest)(nil), // 13: baseca.v1.LoginUserRequest - (*LoginUserResponse)(nil), // 14: baseca.v1.LoginUserResponse - (*UsernameRequest)(nil), // 15: baseca.v1.UsernameRequest - (*QueryParameter)(nil), // 16: baseca.v1.QueryParameter - (*CreateUserRequest)(nil), // 17: baseca.v1.CreateUserRequest - (*UpdateCredentialsRequest)(nil), // 18: baseca.v1.UpdateCredentialsRequest - (*UpdatePermissionsRequest)(nil), // 19: baseca.v1.UpdatePermissionsRequest - (*CreateServiceAccountRequest)(nil), // 20: baseca.v1.CreateServiceAccountRequest - (*CreateServiceAccountResponse)(nil), // 21: baseca.v1.CreateServiceAccountResponse - (*ServiceAccount)(nil), // 22: baseca.v1.ServiceAccount - (*ServiceAccounts)(nil), // 23: baseca.v1.ServiceAccounts - (*NodeAttestation)(nil), // 24: baseca.v1.NodeAttestation - (*AWSInstanceIdentityDocument)(nil), // 25: baseca.v1.AWSInstanceIdentityDocument - (*ServiceAccountId)(nil), // 26: baseca.v1.ServiceAccountId - (*ServiceAccountName)(nil), // 27: baseca.v1.ServiceAccountName - (*ProvisionServiceAccountRequest)(nil), // 28: baseca.v1.ProvisionServiceAccountRequest - (*ProvisionServiceAccountResponse)(nil), // 29: baseca.v1.ProvisionServiceAccountResponse - (*HealthCheckRequest)(nil), // 30: baseca.v1.HealthCheckRequest - (*HealthCheckResponse)(nil), // 31: baseca.v1.HealthCheckResponse - nil, // 32: baseca.v1.AWSInstanceIdentityDocument.InstanceTagsEntry - (*timestamppb.Timestamp)(nil), // 33: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 34: google.protobuf.Empty + (HealthCheckResponse_ServingStatus)(0), // 0: baseca.v1.HealthCheckResponse.ServingStatus + (*CertificateParameter)(nil), // 1: baseca.v1.CertificateParameter + (*CertificatesParameter)(nil), // 2: baseca.v1.CertificatesParameter + (*CertificateAuthorityParameter)(nil), // 3: baseca.v1.CertificateAuthorityParameter + (*CertificateSigningRequest)(nil), // 4: baseca.v1.CertificateSigningRequest + (*SignedCertificate)(nil), // 5: baseca.v1.SignedCertificate + (*CertificateSerialNumber)(nil), // 6: baseca.v1.CertificateSerialNumber + (*ListCertificatesRequest)(nil), // 7: baseca.v1.ListCertificatesRequest + (*RevokeCertificateRequest)(nil), // 8: baseca.v1.RevokeCertificateRequest + (*RevokeCertificateResponse)(nil), // 9: baseca.v1.RevokeCertificateResponse + (*OperationsSignRequest)(nil), // 10: baseca.v1.OperationsSignRequest + (*Environment)(nil), // 11: baseca.v1.Environment + (*QueryCertificateMetadataRequest)(nil), // 12: baseca.v1.QueryCertificateMetadataRequest + (*User)(nil), // 13: baseca.v1.User + (*Users)(nil), // 14: baseca.v1.Users + (*LoginUserRequest)(nil), // 15: baseca.v1.LoginUserRequest + (*LoginUserResponse)(nil), // 16: baseca.v1.LoginUserResponse + (*UsernameRequest)(nil), // 17: baseca.v1.UsernameRequest + (*QueryParameter)(nil), // 18: baseca.v1.QueryParameter + (*CreateUserRequest)(nil), // 19: baseca.v1.CreateUserRequest + (*UpdateCredentialsRequest)(nil), // 20: baseca.v1.UpdateCredentialsRequest + (*UpdatePermissionsRequest)(nil), // 21: baseca.v1.UpdatePermissionsRequest + (*CreateServiceAccountRequest)(nil), // 22: baseca.v1.CreateServiceAccountRequest + (*CreateServiceAccountResponse)(nil), // 23: baseca.v1.CreateServiceAccountResponse + (*ServiceAccount)(nil), // 24: baseca.v1.ServiceAccount + (*ServiceAccounts)(nil), // 25: baseca.v1.ServiceAccounts + (*CreateProvisionerAccountRequest)(nil), // 26: baseca.v1.CreateProvisionerAccountRequest + (*CreateProvisionerAccountResponse)(nil), // 27: baseca.v1.CreateProvisionerAccountResponse + (*ProvisionerAccounts)(nil), // 28: baseca.v1.ProvisionerAccounts + (*ProvisionerAccount)(nil), // 29: baseca.v1.ProvisionerAccount + (*NodeAttestation)(nil), // 30: baseca.v1.NodeAttestation + (*AWSInstanceIdentityDocument)(nil), // 31: baseca.v1.AWSInstanceIdentityDocument + (*AccountId)(nil), // 32: baseca.v1.AccountId + (*GetServiceAccountMetadataRequest)(nil), // 33: baseca.v1.GetServiceAccountMetadataRequest + (*ProvisionServiceAccountRequest)(nil), // 34: baseca.v1.ProvisionServiceAccountRequest + (*ProvisionServiceAccountResponse)(nil), // 35: baseca.v1.ProvisionServiceAccountResponse + (*HealthCheckRequest)(nil), // 36: baseca.v1.HealthCheckRequest + (*HealthCheckResponse)(nil), // 37: baseca.v1.HealthCheckResponse + nil, // 38: baseca.v1.AWSInstanceIdentityDocument.InstanceTagsEntry + (*timestamppb.Timestamp)(nil), // 39: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 40: google.protobuf.Empty } var file_baseca_v1_api_proto_depIdxs = []int32{ - 33, // 0: baseca.v1.CertificateParameter.expiration_date:type_name -> google.protobuf.Timestamp - 33, // 1: baseca.v1.CertificateParameter.issued_date:type_name -> google.protobuf.Timestamp - 33, // 2: baseca.v1.CertificateParameter.revoke_date:type_name -> google.protobuf.Timestamp + 39, // 0: baseca.v1.CertificateParameter.expiration_date:type_name -> google.protobuf.Timestamp + 39, // 1: baseca.v1.CertificateParameter.issued_date:type_name -> google.protobuf.Timestamp + 39, // 2: baseca.v1.CertificateParameter.revoke_date:type_name -> google.protobuf.Timestamp 1, // 3: baseca.v1.CertificatesParameter.certificates:type_name -> baseca.v1.CertificateParameter 1, // 4: baseca.v1.SignedCertificate.metadata:type_name -> baseca.v1.CertificateParameter - 33, // 5: baseca.v1.RevokeCertificateResponse.revocation_date:type_name -> google.protobuf.Timestamp + 39, // 5: baseca.v1.RevokeCertificateResponse.revocation_date:type_name -> google.protobuf.Timestamp 3, // 6: baseca.v1.OperationsSignRequest.certificate_authority:type_name -> baseca.v1.CertificateAuthorityParameter - 33, // 7: baseca.v1.User.credential_changed_at:type_name -> google.protobuf.Timestamp - 33, // 8: baseca.v1.User.created_at:type_name -> google.protobuf.Timestamp - 11, // 9: baseca.v1.Users.users:type_name -> baseca.v1.User - 11, // 10: baseca.v1.LoginUserResponse.user:type_name -> baseca.v1.User - 24, // 11: baseca.v1.CreateServiceAccountRequest.node_attestation:type_name -> baseca.v1.NodeAttestation - 24, // 12: baseca.v1.CreateServiceAccountResponse.node_attestation:type_name -> baseca.v1.NodeAttestation - 33, // 13: baseca.v1.CreateServiceAccountResponse.created_at:type_name -> google.protobuf.Timestamp - 24, // 14: baseca.v1.ServiceAccount.node_attestation:type_name -> baseca.v1.NodeAttestation - 33, // 15: baseca.v1.ServiceAccount.created_at:type_name -> google.protobuf.Timestamp - 22, // 16: baseca.v1.ServiceAccounts.service_accounts:type_name -> baseca.v1.ServiceAccount - 25, // 17: baseca.v1.NodeAttestation.aws_iid:type_name -> baseca.v1.AWSInstanceIdentityDocument - 32, // 18: baseca.v1.AWSInstanceIdentityDocument.instance_tags:type_name -> baseca.v1.AWSInstanceIdentityDocument.InstanceTagsEntry - 20, // 19: baseca.v1.ProvisionServiceAccountRequest.account:type_name -> baseca.v1.CreateServiceAccountRequest - 21, // 20: baseca.v1.ProvisionServiceAccountResponse.account:type_name -> baseca.v1.CreateServiceAccountResponse - 0, // 21: baseca.v1.HealthCheckResponse.status:type_name -> baseca.v1.HealthCheckResponse.ServingStatus - 4, // 22: baseca.v1.Certificate.SignCSR:input_type -> baseca.v1.CertificateSigningRequest - 6, // 23: baseca.v1.Certificate.GetCertificate:input_type -> baseca.v1.CertificateSerialNumber - 7, // 24: baseca.v1.Certificate.ListCertificates:input_type -> baseca.v1.ListCertificatesRequest - 8, // 25: baseca.v1.Certificate.RevokeCertificate:input_type -> baseca.v1.RevokeCertificateRequest - 10, // 26: baseca.v1.Certificate.OperationsSignCSR:input_type -> baseca.v1.OperationsSignRequest - 13, // 27: baseca.v1.Account.LoginUser:input_type -> baseca.v1.LoginUserRequest - 15, // 28: baseca.v1.Account.DeleteUser:input_type -> baseca.v1.UsernameRequest - 15, // 29: baseca.v1.Account.GetUser:input_type -> baseca.v1.UsernameRequest - 16, // 30: baseca.v1.Account.ListUsers:input_type -> baseca.v1.QueryParameter - 17, // 31: baseca.v1.Account.CreateUser:input_type -> baseca.v1.CreateUserRequest - 18, // 32: baseca.v1.Account.UpdateUserCredentials:input_type -> baseca.v1.UpdateCredentialsRequest - 19, // 33: baseca.v1.Account.UpdateUserPermissions:input_type -> baseca.v1.UpdatePermissionsRequest - 20, // 34: baseca.v1.Service.CreateServiceAccount:input_type -> baseca.v1.CreateServiceAccountRequest - 28, // 35: baseca.v1.Service.ProvisionServiceAccount:input_type -> baseca.v1.ProvisionServiceAccountRequest - 16, // 36: baseca.v1.Service.ListServiceAccounts:input_type -> baseca.v1.QueryParameter - 26, // 37: baseca.v1.Service.GetServiceAccountUuid:input_type -> baseca.v1.ServiceAccountId - 27, // 38: baseca.v1.Service.GetServiceAccountName:input_type -> baseca.v1.ServiceAccountName - 26, // 39: baseca.v1.Service.DeleteServiceAccount:input_type -> baseca.v1.ServiceAccountId - 30, // 40: baseca.v1.Health.Check:input_type -> baseca.v1.HealthCheckRequest - 5, // 41: baseca.v1.Certificate.SignCSR:output_type -> baseca.v1.SignedCertificate - 1, // 42: baseca.v1.Certificate.GetCertificate:output_type -> baseca.v1.CertificateParameter - 2, // 43: baseca.v1.Certificate.ListCertificates:output_type -> baseca.v1.CertificatesParameter - 9, // 44: baseca.v1.Certificate.RevokeCertificate:output_type -> baseca.v1.RevokeCertificateResponse - 5, // 45: baseca.v1.Certificate.OperationsSignCSR:output_type -> baseca.v1.SignedCertificate - 14, // 46: baseca.v1.Account.LoginUser:output_type -> baseca.v1.LoginUserResponse - 34, // 47: baseca.v1.Account.DeleteUser:output_type -> google.protobuf.Empty - 11, // 48: baseca.v1.Account.GetUser:output_type -> baseca.v1.User - 12, // 49: baseca.v1.Account.ListUsers:output_type -> baseca.v1.Users - 11, // 50: baseca.v1.Account.CreateUser:output_type -> baseca.v1.User - 11, // 51: baseca.v1.Account.UpdateUserCredentials:output_type -> baseca.v1.User - 11, // 52: baseca.v1.Account.UpdateUserPermissions:output_type -> baseca.v1.User - 21, // 53: baseca.v1.Service.CreateServiceAccount:output_type -> baseca.v1.CreateServiceAccountResponse - 29, // 54: baseca.v1.Service.ProvisionServiceAccount:output_type -> baseca.v1.ProvisionServiceAccountResponse - 23, // 55: baseca.v1.Service.ListServiceAccounts:output_type -> baseca.v1.ServiceAccounts - 22, // 56: baseca.v1.Service.GetServiceAccountUuid:output_type -> baseca.v1.ServiceAccount - 23, // 57: baseca.v1.Service.GetServiceAccountName:output_type -> baseca.v1.ServiceAccounts - 34, // 58: baseca.v1.Service.DeleteServiceAccount:output_type -> google.protobuf.Empty - 31, // 59: baseca.v1.Health.Check:output_type -> baseca.v1.HealthCheckResponse - 41, // [41:60] is the sub-list for method output_type - 22, // [22:41] is the sub-list for method input_type - 22, // [22:22] is the sub-list for extension type_name - 22, // [22:22] is the sub-list for extension extendee - 0, // [0:22] is the sub-list for field type_name + 39, // 7: baseca.v1.User.credential_changed_at:type_name -> google.protobuf.Timestamp + 39, // 8: baseca.v1.User.created_at:type_name -> google.protobuf.Timestamp + 13, // 9: baseca.v1.Users.users:type_name -> baseca.v1.User + 13, // 10: baseca.v1.LoginUserResponse.user:type_name -> baseca.v1.User + 30, // 11: baseca.v1.CreateServiceAccountRequest.node_attestation:type_name -> baseca.v1.NodeAttestation + 30, // 12: baseca.v1.CreateServiceAccountResponse.node_attestation:type_name -> baseca.v1.NodeAttestation + 39, // 13: baseca.v1.CreateServiceAccountResponse.created_at:type_name -> google.protobuf.Timestamp + 30, // 14: baseca.v1.ServiceAccount.node_attestation:type_name -> baseca.v1.NodeAttestation + 39, // 15: baseca.v1.ServiceAccount.created_at:type_name -> google.protobuf.Timestamp + 24, // 16: baseca.v1.ServiceAccounts.service_accounts:type_name -> baseca.v1.ServiceAccount + 30, // 17: baseca.v1.CreateProvisionerAccountRequest.node_attestation:type_name -> baseca.v1.NodeAttestation + 30, // 18: baseca.v1.CreateProvisionerAccountResponse.node_attestation:type_name -> baseca.v1.NodeAttestation + 39, // 19: baseca.v1.CreateProvisionerAccountResponse.created_at:type_name -> google.protobuf.Timestamp + 29, // 20: baseca.v1.ProvisionerAccounts.provisioner_accounts:type_name -> baseca.v1.ProvisionerAccount + 30, // 21: baseca.v1.ProvisionerAccount.node_attestation:type_name -> baseca.v1.NodeAttestation + 39, // 22: baseca.v1.ProvisionerAccount.created_at:type_name -> google.protobuf.Timestamp + 31, // 23: baseca.v1.NodeAttestation.aws_iid:type_name -> baseca.v1.AWSInstanceIdentityDocument + 38, // 24: baseca.v1.AWSInstanceIdentityDocument.instance_tags:type_name -> baseca.v1.AWSInstanceIdentityDocument.InstanceTagsEntry + 30, // 25: baseca.v1.ProvisionServiceAccountRequest.node_attestation:type_name -> baseca.v1.NodeAttestation + 30, // 26: baseca.v1.ProvisionServiceAccountResponse.node_attestation:type_name -> baseca.v1.NodeAttestation + 39, // 27: baseca.v1.ProvisionServiceAccountResponse.created_at:type_name -> google.protobuf.Timestamp + 0, // 28: baseca.v1.HealthCheckResponse.status:type_name -> baseca.v1.HealthCheckResponse.ServingStatus + 4, // 29: baseca.v1.Certificate.SignCSR:input_type -> baseca.v1.CertificateSigningRequest + 6, // 30: baseca.v1.Certificate.GetCertificate:input_type -> baseca.v1.CertificateSerialNumber + 7, // 31: baseca.v1.Certificate.ListCertificates:input_type -> baseca.v1.ListCertificatesRequest + 8, // 32: baseca.v1.Certificate.RevokeCertificate:input_type -> baseca.v1.RevokeCertificateRequest + 10, // 33: baseca.v1.Certificate.OperationsSignCSR:input_type -> baseca.v1.OperationsSignRequest + 12, // 34: baseca.v1.Certificate.QueryCertificateMetadata:input_type -> baseca.v1.QueryCertificateMetadataRequest + 15, // 35: baseca.v1.Account.LoginUser:input_type -> baseca.v1.LoginUserRequest + 17, // 36: baseca.v1.Account.DeleteUser:input_type -> baseca.v1.UsernameRequest + 17, // 37: baseca.v1.Account.GetUser:input_type -> baseca.v1.UsernameRequest + 18, // 38: baseca.v1.Account.ListUsers:input_type -> baseca.v1.QueryParameter + 19, // 39: baseca.v1.Account.CreateUser:input_type -> baseca.v1.CreateUserRequest + 20, // 40: baseca.v1.Account.UpdateUserCredentials:input_type -> baseca.v1.UpdateCredentialsRequest + 21, // 41: baseca.v1.Account.UpdateUserPermissions:input_type -> baseca.v1.UpdatePermissionsRequest + 22, // 42: baseca.v1.Service.CreateServiceAccount:input_type -> baseca.v1.CreateServiceAccountRequest + 26, // 43: baseca.v1.Service.CreateProvisionerAccount:input_type -> baseca.v1.CreateProvisionerAccountRequest + 32, // 44: baseca.v1.Service.GetProvisionerAccount:input_type -> baseca.v1.AccountId + 32, // 45: baseca.v1.Service.GetServiceAccount:input_type -> baseca.v1.AccountId + 33, // 46: baseca.v1.Service.GetServiceAccountMetadata:input_type -> baseca.v1.GetServiceAccountMetadataRequest + 32, // 47: baseca.v1.Service.DeleteServiceAccount:input_type -> baseca.v1.AccountId + 32, // 48: baseca.v1.Service.DeleteProvisionedServiceAccount:input_type -> baseca.v1.AccountId + 32, // 49: baseca.v1.Service.DeleteProvisionerAccount:input_type -> baseca.v1.AccountId + 34, // 50: baseca.v1.Service.ProvisionServiceAccount:input_type -> baseca.v1.ProvisionServiceAccountRequest + 18, // 51: baseca.v1.Service.ListServiceAccounts:input_type -> baseca.v1.QueryParameter + 18, // 52: baseca.v1.Service.ListProvisionerAccounts:input_type -> baseca.v1.QueryParameter + 36, // 53: baseca.v1.Health.Check:input_type -> baseca.v1.HealthCheckRequest + 5, // 54: baseca.v1.Certificate.SignCSR:output_type -> baseca.v1.SignedCertificate + 1, // 55: baseca.v1.Certificate.GetCertificate:output_type -> baseca.v1.CertificateParameter + 2, // 56: baseca.v1.Certificate.ListCertificates:output_type -> baseca.v1.CertificatesParameter + 9, // 57: baseca.v1.Certificate.RevokeCertificate:output_type -> baseca.v1.RevokeCertificateResponse + 5, // 58: baseca.v1.Certificate.OperationsSignCSR:output_type -> baseca.v1.SignedCertificate + 2, // 59: baseca.v1.Certificate.QueryCertificateMetadata:output_type -> baseca.v1.CertificatesParameter + 16, // 60: baseca.v1.Account.LoginUser:output_type -> baseca.v1.LoginUserResponse + 40, // 61: baseca.v1.Account.DeleteUser:output_type -> google.protobuf.Empty + 13, // 62: baseca.v1.Account.GetUser:output_type -> baseca.v1.User + 14, // 63: baseca.v1.Account.ListUsers:output_type -> baseca.v1.Users + 13, // 64: baseca.v1.Account.CreateUser:output_type -> baseca.v1.User + 13, // 65: baseca.v1.Account.UpdateUserCredentials:output_type -> baseca.v1.User + 13, // 66: baseca.v1.Account.UpdateUserPermissions:output_type -> baseca.v1.User + 23, // 67: baseca.v1.Service.CreateServiceAccount:output_type -> baseca.v1.CreateServiceAccountResponse + 27, // 68: baseca.v1.Service.CreateProvisionerAccount:output_type -> baseca.v1.CreateProvisionerAccountResponse + 29, // 69: baseca.v1.Service.GetProvisionerAccount:output_type -> baseca.v1.ProvisionerAccount + 24, // 70: baseca.v1.Service.GetServiceAccount:output_type -> baseca.v1.ServiceAccount + 25, // 71: baseca.v1.Service.GetServiceAccountMetadata:output_type -> baseca.v1.ServiceAccounts + 40, // 72: baseca.v1.Service.DeleteServiceAccount:output_type -> google.protobuf.Empty + 40, // 73: baseca.v1.Service.DeleteProvisionedServiceAccount:output_type -> google.protobuf.Empty + 40, // 74: baseca.v1.Service.DeleteProvisionerAccount:output_type -> google.protobuf.Empty + 35, // 75: baseca.v1.Service.ProvisionServiceAccount:output_type -> baseca.v1.ProvisionServiceAccountResponse + 25, // 76: baseca.v1.Service.ListServiceAccounts:output_type -> baseca.v1.ServiceAccounts + 28, // 77: baseca.v1.Service.ListProvisionerAccounts:output_type -> baseca.v1.ProvisionerAccounts + 37, // 78: baseca.v1.Health.Check:output_type -> baseca.v1.HealthCheckResponse + 54, // [54:79] is the sub-list for method output_type + 29, // [29:54] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name } func init() { file_baseca_v1_api_proto_init() } @@ -2924,7 +3977,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*User); i { + switch v := v.(*Environment); i { case 0: return &v.state case 1: @@ -2936,7 +3989,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Users); i { + switch v := v.(*QueryCertificateMetadataRequest); i { case 0: return &v.state case 1: @@ -2948,7 +4001,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginUserRequest); i { + switch v := v.(*User); i { case 0: return &v.state case 1: @@ -2960,7 +4013,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginUserResponse); i { + switch v := v.(*Users); i { case 0: return &v.state case 1: @@ -2972,7 +4025,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UsernameRequest); i { + switch v := v.(*LoginUserRequest); i { case 0: return &v.state case 1: @@ -2984,7 +4037,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryParameter); i { + switch v := v.(*LoginUserResponse); i { case 0: return &v.state case 1: @@ -2996,7 +4049,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateUserRequest); i { + switch v := v.(*UsernameRequest); i { case 0: return &v.state case 1: @@ -3008,7 +4061,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateCredentialsRequest); i { + switch v := v.(*QueryParameter); i { case 0: return &v.state case 1: @@ -3020,7 +4073,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdatePermissionsRequest); i { + switch v := v.(*CreateUserRequest); i { case 0: return &v.state case 1: @@ -3032,7 +4085,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateServiceAccountRequest); i { + switch v := v.(*UpdateCredentialsRequest); i { case 0: return &v.state case 1: @@ -3044,7 +4097,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateServiceAccountResponse); i { + switch v := v.(*UpdatePermissionsRequest); i { case 0: return &v.state case 1: @@ -3056,7 +4109,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServiceAccount); i { + switch v := v.(*CreateServiceAccountRequest); i { case 0: return &v.state case 1: @@ -3068,7 +4121,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServiceAccounts); i { + switch v := v.(*CreateServiceAccountResponse); i { case 0: return &v.state case 1: @@ -3080,7 +4133,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NodeAttestation); i { + switch v := v.(*ServiceAccount); i { case 0: return &v.state case 1: @@ -3092,7 +4145,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AWSInstanceIdentityDocument); i { + switch v := v.(*ServiceAccounts); i { case 0: return &v.state case 1: @@ -3104,7 +4157,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServiceAccountId); i { + switch v := v.(*CreateProvisionerAccountRequest); i { case 0: return &v.state case 1: @@ -3116,7 +4169,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ServiceAccountName); i { + switch v := v.(*CreateProvisionerAccountResponse); i { case 0: return &v.state case 1: @@ -3128,7 +4181,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProvisionServiceAccountRequest); i { + switch v := v.(*ProvisionerAccounts); i { case 0: return &v.state case 1: @@ -3140,7 +4193,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProvisionServiceAccountResponse); i { + switch v := v.(*ProvisionerAccount); i { case 0: return &v.state case 1: @@ -3152,7 +4205,7 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HealthCheckRequest); i { + switch v := v.(*NodeAttestation); i { case 0: return &v.state case 1: @@ -3164,6 +4217,78 @@ func file_baseca_v1_api_proto_init() { } } file_baseca_v1_api_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AWSInstanceIdentityDocument); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_baseca_v1_api_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccountId); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_baseca_v1_api_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetServiceAccountMetadataRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_baseca_v1_api_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProvisionServiceAccountRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_baseca_v1_api_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProvisionServiceAccountResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_baseca_v1_api_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HealthCheckRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_baseca_v1_api_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HealthCheckResponse); i { case 0: return &v.state @@ -3176,14 +4301,16 @@ func file_baseca_v1_api_proto_init() { } } } - file_baseca_v1_api_proto_msgTypes[19].OneofWrappers = []interface{}{} + file_baseca_v1_api_proto_msgTypes[9].OneofWrappers = []interface{}{} + file_baseca_v1_api_proto_msgTypes[21].OneofWrappers = []interface{}{} + file_baseca_v1_api_proto_msgTypes[25].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_baseca_v1_api_proto_rawDesc, NumEnums: 1, - NumMessages: 32, + NumMessages: 38, NumExtensions: 0, NumServices: 4, }, diff --git a/gen/go/baseca/v1/api_grpc.pb.go b/gen/go/baseca/v1/api_grpc.pb.go index 8308499..aa99356 100644 --- a/gen/go/baseca/v1/api_grpc.pb.go +++ b/gen/go/baseca/v1/api_grpc.pb.go @@ -28,6 +28,7 @@ type CertificateClient interface { ListCertificates(ctx context.Context, in *ListCertificatesRequest, opts ...grpc.CallOption) (*CertificatesParameter, error) RevokeCertificate(ctx context.Context, in *RevokeCertificateRequest, opts ...grpc.CallOption) (*RevokeCertificateResponse, error) OperationsSignCSR(ctx context.Context, in *OperationsSignRequest, opts ...grpc.CallOption) (*SignedCertificate, error) + QueryCertificateMetadata(ctx context.Context, in *QueryCertificateMetadataRequest, opts ...grpc.CallOption) (*CertificatesParameter, error) } type certificateClient struct { @@ -83,6 +84,15 @@ func (c *certificateClient) OperationsSignCSR(ctx context.Context, in *Operation return out, nil } +func (c *certificateClient) QueryCertificateMetadata(ctx context.Context, in *QueryCertificateMetadataRequest, opts ...grpc.CallOption) (*CertificatesParameter, error) { + out := new(CertificatesParameter) + err := c.cc.Invoke(ctx, "/baseca.v1.Certificate/QueryCertificateMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // CertificateServer is the server API for Certificate service. // All implementations must embed UnimplementedCertificateServer // for forward compatibility @@ -92,6 +102,7 @@ type CertificateServer interface { ListCertificates(context.Context, *ListCertificatesRequest) (*CertificatesParameter, error) RevokeCertificate(context.Context, *RevokeCertificateRequest) (*RevokeCertificateResponse, error) OperationsSignCSR(context.Context, *OperationsSignRequest) (*SignedCertificate, error) + QueryCertificateMetadata(context.Context, *QueryCertificateMetadataRequest) (*CertificatesParameter, error) mustEmbedUnimplementedCertificateServer() } @@ -114,6 +125,9 @@ func (UnimplementedCertificateServer) RevokeCertificate(context.Context, *Revoke func (UnimplementedCertificateServer) OperationsSignCSR(context.Context, *OperationsSignRequest) (*SignedCertificate, error) { return nil, status.Errorf(codes.Unimplemented, "method OperationsSignCSR not implemented") } +func (UnimplementedCertificateServer) QueryCertificateMetadata(context.Context, *QueryCertificateMetadataRequest) (*CertificatesParameter, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryCertificateMetadata not implemented") +} func (UnimplementedCertificateServer) mustEmbedUnimplementedCertificateServer() {} // UnsafeCertificateServer may be embedded to opt out of forward compatibility for this service. @@ -217,6 +231,24 @@ func _Certificate_OperationsSignCSR_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _Certificate_QueryCertificateMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryCertificateMetadataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CertificateServer).QueryCertificateMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/baseca.v1.Certificate/QueryCertificateMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CertificateServer).QueryCertificateMetadata(ctx, req.(*QueryCertificateMetadataRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Certificate_ServiceDesc is the grpc.ServiceDesc for Certificate service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -244,6 +276,10 @@ var Certificate_ServiceDesc = grpc.ServiceDesc{ MethodName: "OperationsSignCSR", Handler: _Certificate_OperationsSignCSR_Handler, }, + { + MethodName: "QueryCertificateMetadata", + Handler: _Certificate_QueryCertificateMetadata_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "baseca/v1/api.proto", @@ -556,11 +592,16 @@ var Account_ServiceDesc = grpc.ServiceDesc{ // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ServiceClient interface { CreateServiceAccount(ctx context.Context, in *CreateServiceAccountRequest, opts ...grpc.CallOption) (*CreateServiceAccountResponse, error) + CreateProvisionerAccount(ctx context.Context, in *CreateProvisionerAccountRequest, opts ...grpc.CallOption) (*CreateProvisionerAccountResponse, error) + GetProvisionerAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*ProvisionerAccount, error) + GetServiceAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*ServiceAccount, error) + GetServiceAccountMetadata(ctx context.Context, in *GetServiceAccountMetadataRequest, opts ...grpc.CallOption) (*ServiceAccounts, error) + DeleteServiceAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) + DeleteProvisionedServiceAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) + DeleteProvisionerAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) ProvisionServiceAccount(ctx context.Context, in *ProvisionServiceAccountRequest, opts ...grpc.CallOption) (*ProvisionServiceAccountResponse, error) ListServiceAccounts(ctx context.Context, in *QueryParameter, opts ...grpc.CallOption) (*ServiceAccounts, error) - GetServiceAccountUuid(ctx context.Context, in *ServiceAccountId, opts ...grpc.CallOption) (*ServiceAccount, error) - GetServiceAccountName(ctx context.Context, in *ServiceAccountName, opts ...grpc.CallOption) (*ServiceAccounts, error) - DeleteServiceAccount(ctx context.Context, in *ServiceAccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) + ListProvisionerAccounts(ctx context.Context, in *QueryParameter, opts ...grpc.CallOption) (*ProvisionerAccounts, error) } type serviceClient struct { @@ -580,43 +621,43 @@ func (c *serviceClient) CreateServiceAccount(ctx context.Context, in *CreateServ return out, nil } -func (c *serviceClient) ProvisionServiceAccount(ctx context.Context, in *ProvisionServiceAccountRequest, opts ...grpc.CallOption) (*ProvisionServiceAccountResponse, error) { - out := new(ProvisionServiceAccountResponse) - err := c.cc.Invoke(ctx, "/baseca.v1.Service/ProvisionServiceAccount", in, out, opts...) +func (c *serviceClient) CreateProvisionerAccount(ctx context.Context, in *CreateProvisionerAccountRequest, opts ...grpc.CallOption) (*CreateProvisionerAccountResponse, error) { + out := new(CreateProvisionerAccountResponse) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/CreateProvisionerAccount", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *serviceClient) ListServiceAccounts(ctx context.Context, in *QueryParameter, opts ...grpc.CallOption) (*ServiceAccounts, error) { - out := new(ServiceAccounts) - err := c.cc.Invoke(ctx, "/baseca.v1.Service/ListServiceAccounts", in, out, opts...) +func (c *serviceClient) GetProvisionerAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*ProvisionerAccount, error) { + out := new(ProvisionerAccount) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/GetProvisionerAccount", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *serviceClient) GetServiceAccountUuid(ctx context.Context, in *ServiceAccountId, opts ...grpc.CallOption) (*ServiceAccount, error) { +func (c *serviceClient) GetServiceAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*ServiceAccount, error) { out := new(ServiceAccount) - err := c.cc.Invoke(ctx, "/baseca.v1.Service/GetServiceAccountUuid", in, out, opts...) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/GetServiceAccount", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *serviceClient) GetServiceAccountName(ctx context.Context, in *ServiceAccountName, opts ...grpc.CallOption) (*ServiceAccounts, error) { +func (c *serviceClient) GetServiceAccountMetadata(ctx context.Context, in *GetServiceAccountMetadataRequest, opts ...grpc.CallOption) (*ServiceAccounts, error) { out := new(ServiceAccounts) - err := c.cc.Invoke(ctx, "/baseca.v1.Service/GetServiceAccountName", in, out, opts...) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/GetServiceAccountMetadata", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *serviceClient) DeleteServiceAccount(ctx context.Context, in *ServiceAccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) { +func (c *serviceClient) DeleteServiceAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) err := c.cc.Invoke(ctx, "/baseca.v1.Service/DeleteServiceAccount", in, out, opts...) if err != nil { @@ -625,16 +666,66 @@ func (c *serviceClient) DeleteServiceAccount(ctx context.Context, in *ServiceAcc return out, nil } +func (c *serviceClient) DeleteProvisionedServiceAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/DeleteProvisionedServiceAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) DeleteProvisionerAccount(ctx context.Context, in *AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/DeleteProvisionerAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) ProvisionServiceAccount(ctx context.Context, in *ProvisionServiceAccountRequest, opts ...grpc.CallOption) (*ProvisionServiceAccountResponse, error) { + out := new(ProvisionServiceAccountResponse) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/ProvisionServiceAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) ListServiceAccounts(ctx context.Context, in *QueryParameter, opts ...grpc.CallOption) (*ServiceAccounts, error) { + out := new(ServiceAccounts) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/ListServiceAccounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) ListProvisionerAccounts(ctx context.Context, in *QueryParameter, opts ...grpc.CallOption) (*ProvisionerAccounts, error) { + out := new(ProvisionerAccounts) + err := c.cc.Invoke(ctx, "/baseca.v1.Service/ListProvisionerAccounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ServiceServer is the server API for Service service. // All implementations must embed UnimplementedServiceServer // for forward compatibility type ServiceServer interface { CreateServiceAccount(context.Context, *CreateServiceAccountRequest) (*CreateServiceAccountResponse, error) + CreateProvisionerAccount(context.Context, *CreateProvisionerAccountRequest) (*CreateProvisionerAccountResponse, error) + GetProvisionerAccount(context.Context, *AccountId) (*ProvisionerAccount, error) + GetServiceAccount(context.Context, *AccountId) (*ServiceAccount, error) + GetServiceAccountMetadata(context.Context, *GetServiceAccountMetadataRequest) (*ServiceAccounts, error) + DeleteServiceAccount(context.Context, *AccountId) (*emptypb.Empty, error) + DeleteProvisionedServiceAccount(context.Context, *AccountId) (*emptypb.Empty, error) + DeleteProvisionerAccount(context.Context, *AccountId) (*emptypb.Empty, error) ProvisionServiceAccount(context.Context, *ProvisionServiceAccountRequest) (*ProvisionServiceAccountResponse, error) ListServiceAccounts(context.Context, *QueryParameter) (*ServiceAccounts, error) - GetServiceAccountUuid(context.Context, *ServiceAccountId) (*ServiceAccount, error) - GetServiceAccountName(context.Context, *ServiceAccountName) (*ServiceAccounts, error) - DeleteServiceAccount(context.Context, *ServiceAccountId) (*emptypb.Empty, error) + ListProvisionerAccounts(context.Context, *QueryParameter) (*ProvisionerAccounts, error) mustEmbedUnimplementedServiceServer() } @@ -645,20 +736,35 @@ type UnimplementedServiceServer struct { func (UnimplementedServiceServer) CreateServiceAccount(context.Context, *CreateServiceAccountRequest) (*CreateServiceAccountResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateServiceAccount not implemented") } +func (UnimplementedServiceServer) CreateProvisionerAccount(context.Context, *CreateProvisionerAccountRequest) (*CreateProvisionerAccountResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateProvisionerAccount not implemented") +} +func (UnimplementedServiceServer) GetProvisionerAccount(context.Context, *AccountId) (*ProvisionerAccount, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetProvisionerAccount not implemented") +} +func (UnimplementedServiceServer) GetServiceAccount(context.Context, *AccountId) (*ServiceAccount, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetServiceAccount not implemented") +} +func (UnimplementedServiceServer) GetServiceAccountMetadata(context.Context, *GetServiceAccountMetadataRequest) (*ServiceAccounts, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetServiceAccountMetadata not implemented") +} +func (UnimplementedServiceServer) DeleteServiceAccount(context.Context, *AccountId) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteServiceAccount not implemented") +} +func (UnimplementedServiceServer) DeleteProvisionedServiceAccount(context.Context, *AccountId) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteProvisionedServiceAccount not implemented") +} +func (UnimplementedServiceServer) DeleteProvisionerAccount(context.Context, *AccountId) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteProvisionerAccount not implemented") +} func (UnimplementedServiceServer) ProvisionServiceAccount(context.Context, *ProvisionServiceAccountRequest) (*ProvisionServiceAccountResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ProvisionServiceAccount not implemented") } func (UnimplementedServiceServer) ListServiceAccounts(context.Context, *QueryParameter) (*ServiceAccounts, error) { return nil, status.Errorf(codes.Unimplemented, "method ListServiceAccounts not implemented") } -func (UnimplementedServiceServer) GetServiceAccountUuid(context.Context, *ServiceAccountId) (*ServiceAccount, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetServiceAccountUuid not implemented") -} -func (UnimplementedServiceServer) GetServiceAccountName(context.Context, *ServiceAccountName) (*ServiceAccounts, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetServiceAccountName not implemented") -} -func (UnimplementedServiceServer) DeleteServiceAccount(context.Context, *ServiceAccountId) (*emptypb.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method DeleteServiceAccount not implemented") +func (UnimplementedServiceServer) ListProvisionerAccounts(context.Context, *QueryParameter) (*ProvisionerAccounts, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListProvisionerAccounts not implemented") } func (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {} @@ -691,80 +797,80 @@ func _Service_CreateServiceAccount_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } -func _Service_ProvisionServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ProvisionServiceAccountRequest) +func _Service_CreateProvisionerAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateProvisionerAccountRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(ServiceServer).ProvisionServiceAccount(ctx, in) + return srv.(ServiceServer).CreateProvisionerAccount(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/baseca.v1.Service/ProvisionServiceAccount", + FullMethod: "/baseca.v1.Service/CreateProvisionerAccount", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ServiceServer).ProvisionServiceAccount(ctx, req.(*ProvisionServiceAccountRequest)) + return srv.(ServiceServer).CreateProvisionerAccount(ctx, req.(*CreateProvisionerAccountRequest)) } return interceptor(ctx, in, info, handler) } -func _Service_ListServiceAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryParameter) +func _Service_GetProvisionerAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountId) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(ServiceServer).ListServiceAccounts(ctx, in) + return srv.(ServiceServer).GetProvisionerAccount(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/baseca.v1.Service/ListServiceAccounts", + FullMethod: "/baseca.v1.Service/GetProvisionerAccount", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ServiceServer).ListServiceAccounts(ctx, req.(*QueryParameter)) + return srv.(ServiceServer).GetProvisionerAccount(ctx, req.(*AccountId)) } return interceptor(ctx, in, info, handler) } -func _Service_GetServiceAccountUuid_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ServiceAccountId) +func _Service_GetServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountId) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(ServiceServer).GetServiceAccountUuid(ctx, in) + return srv.(ServiceServer).GetServiceAccount(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/baseca.v1.Service/GetServiceAccountUuid", + FullMethod: "/baseca.v1.Service/GetServiceAccount", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ServiceServer).GetServiceAccountUuid(ctx, req.(*ServiceAccountId)) + return srv.(ServiceServer).GetServiceAccount(ctx, req.(*AccountId)) } return interceptor(ctx, in, info, handler) } -func _Service_GetServiceAccountName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ServiceAccountName) +func _Service_GetServiceAccountMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetServiceAccountMetadataRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(ServiceServer).GetServiceAccountName(ctx, in) + return srv.(ServiceServer).GetServiceAccountMetadata(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/baseca.v1.Service/GetServiceAccountName", + FullMethod: "/baseca.v1.Service/GetServiceAccountMetadata", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ServiceServer).GetServiceAccountName(ctx, req.(*ServiceAccountName)) + return srv.(ServiceServer).GetServiceAccountMetadata(ctx, req.(*GetServiceAccountMetadataRequest)) } return interceptor(ctx, in, info, handler) } func _Service_DeleteServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ServiceAccountId) + in := new(AccountId) if err := dec(in); err != nil { return nil, err } @@ -776,7 +882,97 @@ func _Service_DeleteServiceAccount_Handler(srv interface{}, ctx context.Context, FullMethod: "/baseca.v1.Service/DeleteServiceAccount", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ServiceServer).DeleteServiceAccount(ctx, req.(*ServiceAccountId)) + return srv.(ServiceServer).DeleteServiceAccount(ctx, req.(*AccountId)) + } + return interceptor(ctx, in, info, handler) +} + +func _Service_DeleteProvisionedServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountId) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).DeleteProvisionedServiceAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/baseca.v1.Service/DeleteProvisionedServiceAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).DeleteProvisionedServiceAccount(ctx, req.(*AccountId)) + } + return interceptor(ctx, in, info, handler) +} + +func _Service_DeleteProvisionerAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountId) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).DeleteProvisionerAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/baseca.v1.Service/DeleteProvisionerAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).DeleteProvisionerAccount(ctx, req.(*AccountId)) + } + return interceptor(ctx, in, info, handler) +} + +func _Service_ProvisionServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ProvisionServiceAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).ProvisionServiceAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/baseca.v1.Service/ProvisionServiceAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).ProvisionServiceAccount(ctx, req.(*ProvisionServiceAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Service_ListServiceAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParameter) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).ListServiceAccounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/baseca.v1.Service/ListServiceAccounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).ListServiceAccounts(ctx, req.(*QueryParameter)) + } + return interceptor(ctx, in, info, handler) +} + +func _Service_ListProvisionerAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParameter) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).ListProvisionerAccounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/baseca.v1.Service/ListProvisionerAccounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).ListProvisionerAccounts(ctx, req.(*QueryParameter)) } return interceptor(ctx, in, info, handler) } @@ -793,25 +989,45 @@ var Service_ServiceDesc = grpc.ServiceDesc{ Handler: _Service_CreateServiceAccount_Handler, }, { - MethodName: "ProvisionServiceAccount", - Handler: _Service_ProvisionServiceAccount_Handler, + MethodName: "CreateProvisionerAccount", + Handler: _Service_CreateProvisionerAccount_Handler, }, { - MethodName: "ListServiceAccounts", - Handler: _Service_ListServiceAccounts_Handler, + MethodName: "GetProvisionerAccount", + Handler: _Service_GetProvisionerAccount_Handler, }, { - MethodName: "GetServiceAccountUuid", - Handler: _Service_GetServiceAccountUuid_Handler, + MethodName: "GetServiceAccount", + Handler: _Service_GetServiceAccount_Handler, }, { - MethodName: "GetServiceAccountName", - Handler: _Service_GetServiceAccountName_Handler, + MethodName: "GetServiceAccountMetadata", + Handler: _Service_GetServiceAccountMetadata_Handler, }, { MethodName: "DeleteServiceAccount", Handler: _Service_DeleteServiceAccount_Handler, }, + { + MethodName: "DeleteProvisionedServiceAccount", + Handler: _Service_DeleteProvisionedServiceAccount_Handler, + }, + { + MethodName: "DeleteProvisionerAccount", + Handler: _Service_DeleteProvisionerAccount_Handler, + }, + { + MethodName: "ProvisionServiceAccount", + Handler: _Service_ProvisionServiceAccount_Handler, + }, + { + MethodName: "ListServiceAccounts", + Handler: _Service_ListServiceAccounts_Handler, + }, + { + MethodName: "ListProvisionerAccounts", + Handler: _Service_ListProvisionerAccounts_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "baseca/v1/api.proto", diff --git a/internal/authentication/authentication.go b/internal/authentication/authentication.go index ecbb9c1..55f0f6d 100644 --- a/internal/authentication/authentication.go +++ b/internal/authentication/authentication.go @@ -21,7 +21,7 @@ func CheckPassword(password string, hashedPassword string) error { } func GenerateClientToken(n int) (string, error) { - const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+`-={}|[]:<>?,./" + const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%^*()-_=+{}[]:;,.?/~" ret := make([]byte, n) for i := 0; i < n; i++ { num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) diff --git a/internal/authentication/payload.go b/internal/authentication/payload.go index b5de257..caa54a7 100644 --- a/internal/authentication/payload.go +++ b/internal/authentication/payload.go @@ -23,6 +23,16 @@ type ServicePayload struct { SANRegularExpression string `json:"regular_expression"` } +type ProvisionerAccountPayload struct { + ClientId uuid.UUID `json:"client_id"` + ProvisionerAccount string `json:"provisioner_account"` + Environments []string `json:"environments"` + ValidSubjectAlternateNames []string `json:"subject_alternate_names"` + MaxCertificateValidity uint32 `json:"max_certificate_validity"` + ExtendedKeys []string `json:"certificate_request_extension"` + RegularExpression string `json:"regular_expression"` +} + type EnrollmentPayload struct { SerialNumber string `json:"serial_number"` } diff --git a/internal/client/acmpca/issue.go b/internal/client/acmpca/issue.go index 2740826..ef2da58 100644 --- a/internal/client/acmpca/issue.go +++ b/internal/client/acmpca/issue.go @@ -18,6 +18,9 @@ import ( const ( _subordinateCACertificate_PathLen0_V1 = "arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0/V1" + _codeSigningCertificate_V1 = "arn:aws:acm-pca:::template/CodeSigningCertificate/V1" + _endEntityServerAuthCertificate_V1 = "arn:aws:acm-pca:::template/EndEntityServerAuthCertificate/V1" + _endEntityClientAuthCertificate_V1 = "arn:aws:acm-pca:::template/EndEntityClientAuthCertificate/V1" ) func (c *PrivateCaClient) IssueCertificateFromTemplate(parameters *apiv1.CertificateAuthorityParameter, csr []byte, template string) (*x509.Certificate, error) { diff --git a/internal/client/firehose/stream.go b/internal/client/firehose/stream.go index b452055..f8aa864 100644 --- a/internal/client/firehose/stream.go +++ b/internal/client/firehose/stream.go @@ -2,13 +2,16 @@ package firehose import ( "context" + "crypto/rand" "encoding/json" "fmt" + "math/big" "time" "github.com/aws/aws-sdk-go-v2/aws" firehose_v2 "github.com/aws/aws-sdk-go-v2/service/firehose" "github.com/aws/aws-sdk-go-v2/service/firehose/types" + "github.com/coinbase/baseca/internal/lib/util" ) type ForwardedEventUploadEvent struct { @@ -23,9 +26,12 @@ type Metadata struct { IssuedDate time.Time `json:"issued_date"` CaSerialNumber string `json:"ca_serial_number"` CertificateAuthorityArn string `json:"certificate_authority_arn"` + Timestamp time.Time `json:"timestamp"` } func (c FirehoseClient) Stream(ctx context.Context, event ForwardedEventUploadEvent) (response *firehose_v2.PutRecordOutput, err error) { + var firehoseErr error + batch, err := json.Marshal(event) if err != nil { return nil, fmt.Errorf("error marshalling firehose event: %s", err) @@ -37,9 +43,22 @@ func (c FirehoseClient) Stream(ctx context.Context, event ForwardedEventUploadEv }, } - record, err := c.Service.PutRecord(ctx, input) - if err != nil { - return nil, fmt.Errorf("error putting firehose record: %s", err) + for _, backoff := range util.BackoffSchedule { + record, err := c.Service.PutRecord(ctx, input) + if err != nil { + firehoseErr = err + + jitterInt, err := rand.Int(rand.Reader, big.NewInt(int64(backoff))) + if err != nil { + return nil, fmt.Errorf("error generating jitter: %s", err) + } + + jitter := time.Duration(jitterInt.Int64()) + time.Sleep(backoff + jitter) + + continue + } + return record, nil } - return record, nil + return nil, fmt.Errorf("error putting firehose record: %s", firehoseErr) } diff --git a/internal/client/redis/client.go b/internal/client/redis/client.go index 13e2f02..fd05c8e 100644 --- a/internal/client/redis/client.go +++ b/internal/client/redis/client.go @@ -27,9 +27,10 @@ type RedisClient struct { Config *config.RedisConfig // Sliding Window - Limit int - Period time.Duration - Window time.Duration + Limit int + Excluded []string + Period time.Duration + Window time.Duration } func NewRedisClient(config *config.Config) (*RedisClient, error) { @@ -54,10 +55,11 @@ func NewRedisClient(config *config.Config) (*RedisClient, error) { } return &RedisClient{ - Client: client, - Config: redisConfig, - Limit: redisConfig.RateLimit, - Period: time.Duration(redisConfig.Period) * time.Minute, - Window: time.Duration(redisConfig.Duration) * time.Minute, + Client: client, + Config: redisConfig, + Limit: redisConfig.RateLimit, + Excluded: redisConfig.ExcludeRateLimit, + Period: time.Duration(redisConfig.Period) * time.Minute, + Window: time.Duration(redisConfig.Duration) * time.Minute, }, nil } diff --git a/internal/client/secretsmanager/query.go b/internal/client/secretsmanager/query.go index 6ef7db2..32cc297 100644 --- a/internal/client/secretsmanager/query.go +++ b/internal/client/secretsmanager/query.go @@ -10,7 +10,7 @@ import ( ) const ( - DATABASE_CREDENTIALS = "password" + DATABASE_CREDENTIALS = "database_credentials" AUTH_PRIVATE_KEY = "auth_private_key" AUTH_PUBLIC_KEY = "auth_public_key" ) diff --git a/internal/config/config.go b/internal/config/config.go index 5657a45..2b19e21 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -34,11 +34,12 @@ type DatabaseConfig struct { } type RedisConfig struct { - Endpoint string `mapstructure:"cluster_endpoint"` - Port string `mapstructure:"port"` - Duration int `mapstructure:"duration"` - Period int `mapstructure:"period"` - RateLimit int `mapstructure:"rate_limit"` + Endpoint string `mapstructure:"cluster_endpoint"` + Port string `mapstructure:"port"` + Duration int `mapstructure:"duration"` + Period int `mapstructure:"period"` + RateLimit int `mapstructure:"rate_limit"` + ExcludeRateLimit []string `mapstructure:"exclude_rate_limit"` } type FirehoseConfig struct { diff --git a/internal/lib/crypto/chain.go b/internal/lib/crypto/chain.go index b496613..b6f2f10 100644 --- a/internal/lib/crypto/chain.go +++ b/internal/lib/crypto/chain.go @@ -21,44 +21,62 @@ const ( _rootCertificate = "/ca-root.crt" ) -func BuildCertificateChain(intermediateCa string, certificate []byte, caCertificate []byte) (*bytes.Buffer, *bytes.Buffer, error) { +func BuildCertificateChain(ca_path string, certificate []byte, subordinate_ca []byte) (*bytes.Buffer, *bytes.Buffer, *bytes.Buffer, error) { var err error leaf_certificate := new(bytes.Buffer) - chained_certificate := new(bytes.Buffer) + intermediate_chained_certificate := new(bytes.Buffer) + root_chained_certificate := new(bytes.Buffer) - intermediate_ca, root_ca, err := getCertificateChain(intermediateCa) + intermediate_ca, root_ca, err := retrieveCertificateAuthority(ca_path) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - // Leaf Certificate + // End Entity Certificate err = pem.Encode(leaf_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - // Certificate Chain - err = pem.Encode(chained_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}) + // Build Intermediate Certificate Chain + err = pem.Encode(intermediate_chained_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}) if err != nil { - return nil, nil, err + return nil, nil, nil, err + } + + var intermediate_chain [][]byte + if intermediate_ca != nil { + intermediate_chain = [][]byte{subordinate_ca, intermediate_ca} + } + + for _, crt := range intermediate_chain { + err = pem.Encode(intermediate_chained_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: crt}) + if err != nil { + return nil, nil, nil, err + } } - // Build the chain based on the existence of intermediate_ca - var chain [][]byte + // Build Root Certificate Chains Depending on Existence of Intermediate CA + err = pem.Encode(root_chained_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}) + if err != nil { + return nil, nil, nil, err + } + + var root_chain [][]byte if intermediate_ca != nil { - chain = [][]byte{caCertificate, intermediate_ca, root_ca} + root_chain = [][]byte{subordinate_ca, intermediate_ca, root_ca} } else { - chain = [][]byte{caCertificate, root_ca} + root_chain = [][]byte{subordinate_ca, root_ca} } - for _, certificate := range chain { - err = pem.Encode(chained_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}) + for _, crt := range root_chain { + err = pem.Encode(root_chained_certificate, &pem.Block{Type: "CERTIFICATE", Bytes: crt}) if err != nil { - return nil, nil, err + return nil, nil, nil, err } } - return leaf_certificate, chained_certificate, nil + return leaf_certificate, intermediate_chained_certificate, root_chained_certificate, nil } func GetSubordinateCaPath(service string) (*string, *string, error) { @@ -77,7 +95,7 @@ func GetSubordinateCaPath(service string) (*string, *string, error) { return &caPath, &keyPath, nil } -func getCertificateChain(service string) ([]byte, []byte, error) { +func retrieveCertificateAuthority(service string) ([]byte, []byte, error) { intermediatePath := filepath.Join(types.SubordinatePath, service+_intermediateCertificate) rootPath := filepath.Join(types.SubordinatePath, service+_rootCertificate) diff --git a/internal/lib/crypto/store.go b/internal/lib/crypto/store.go index 809ff01..6881a69 100644 --- a/internal/lib/crypto/store.go +++ b/internal/lib/crypto/store.go @@ -4,7 +4,6 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -42,7 +41,7 @@ func WriteKeyToFile(service string, privateKey types.AsymmetricKey) error { return fmt.Errorf("private key format not supported") } - if err := ioutil.WriteFile(filePath, pem.EncodeToMemory(pemBlock), os.ModePerm); err != nil { + if err := os.WriteFile(filePath, pem.EncodeToMemory(pemBlock), os.ModePerm); err != nil { return err } diff --git a/internal/lib/util/backoff.go b/internal/lib/util/backoff.go index c1cc344..0a39c58 100644 --- a/internal/lib/util/backoff.go +++ b/internal/lib/util/backoff.go @@ -10,7 +10,7 @@ import ( "github.com/coinbase/baseca/internal/types" ) -var backoffSchedule = []time.Duration{ +var BackoffSchedule = []time.Duration{ 1 * time.Second, 2 * time.Second, 4 * time.Second, @@ -22,7 +22,7 @@ func LockfileBackoff(lockfilePath string) error { _, err := os.OpenFile(filepath.Clean(lockfilePath), os.O_RDONLY, 0400) if err == nil { // Backoff Until Lock File Removed - for _, backoff := range backoffSchedule { + for _, backoff := range BackoffSchedule { _, err = os.OpenFile(filepath.Clean(lockfilePath), os.O_RDONLY, 0400) if errors.Is(err, os.ErrNotExist) { return nil diff --git a/internal/types/certificate.go b/internal/types/certificate.go index 6de9263..941b1d7 100644 --- a/internal/types/certificate.go +++ b/internal/types/certificate.go @@ -48,6 +48,7 @@ type CertificateMetadata struct { Revoked bool RevokedBy string RevokeDate time.Time + Timestamp time.Time } type CertificateRequest struct { diff --git a/internal/v1/accounts/operation_test.go b/internal/v1/accounts/operation_test.go index b39a61c..38b5e8e 100644 --- a/internal/v1/accounts/operation_test.go +++ b/internal/v1/accounts/operation_test.go @@ -20,13 +20,13 @@ func TestDeleteServiceAccount(t *testing.T) { cases := []struct { name string - req *apiv1.ServiceAccountId + req *apiv1.AccountId build func(store *mock.MockStore) check func(t *testing.T, res *emptypb.Empty, err error) }{ { name: "OK", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: service_account_id, }, build: func(store *mock.MockStore) { @@ -38,7 +38,7 @@ func TestDeleteServiceAccount(t *testing.T) { }, { name: "INVALID_UUID", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: "random_string", }, build: func(store *mock.MockStore) {}, @@ -49,7 +49,7 @@ func TestDeleteServiceAccount(t *testing.T) { }, { name: "DB_ERROR", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: service_account_id, }, build: func(store *mock.MockStore) { diff --git a/internal/v1/accounts/operations.go b/internal/v1/accounts/operations.go index 78d742a..7c85906 100644 --- a/internal/v1/accounts/operations.go +++ b/internal/v1/accounts/operations.go @@ -2,6 +2,7 @@ package accounts import ( "context" + "fmt" apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" "github.com/coinbase/baseca/internal/logger" @@ -11,15 +12,30 @@ import ( "google.golang.org/protobuf/types/known/emptypb" ) -func (s *Service) DeleteServiceAccount(ctx context.Context, req *apiv1.ServiceAccountId) (*emptypb.Empty, error) { +func (s *Service) DeleteServiceAccount(ctx context.Context, req *apiv1.AccountId) (*emptypb.Empty, error) { client_id, err := uuid.Parse(req.Uuid) if err != nil { - return &emptypb.Empty{}, logger.RpcError(status.Error(codes.InvalidArgument, "invalid uuid parameter"), err) + return &emptypb.Empty{}, logger.RpcError(status.Error(codes.InvalidArgument, "invalid uuid parameter"), fmt.Errorf("[DeleteServiceAccount] invalid UUID %s", req.Uuid)) } err = s.store.Writer.TxDeleteServiceAccount(ctx, client_id) if err != nil { - return &emptypb.Empty{}, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + return &emptypb.Empty{}, logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("[DeleteServiceAccount] deletion transaction failed %s", err)) + } + + return &emptypb.Empty{}, nil +} + +func (s *Service) DeleteProvisionerAccount(ctx context.Context, req *apiv1.AccountId) (*emptypb.Empty, error) { + client_id, err := uuid.Parse(req.Uuid) + if err != nil { + return &emptypb.Empty{}, logger.RpcError(status.Error(codes.InvalidArgument, "invalid uuid parameter"), fmt.Errorf("[DeleteProvisionerAccount] invalid UUID %s", req.Uuid)) + } + + err = s.store.Writer.TxDeleteProvisionerAccount(ctx, client_id) + + if err != nil { + return &emptypb.Empty{}, logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("[DeleteProvisionerAccount] deletion transaction failed %s", err)) } return &emptypb.Empty{}, nil diff --git a/internal/v1/accounts/provision.go b/internal/v1/accounts/provision.go new file mode 100644 index 0000000..a89771a --- /dev/null +++ b/internal/v1/accounts/provision.go @@ -0,0 +1,383 @@ +package accounts + +import ( + "context" + "database/sql" + "fmt" + "regexp" + "time" + + db "github.com/coinbase/baseca/db/sqlc" + apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" + "github.com/coinbase/baseca/internal/attestor/aws_iid" + "github.com/coinbase/baseca/internal/authentication" + "github.com/coinbase/baseca/internal/logger" + "github.com/coinbase/baseca/internal/types" + "github.com/coinbase/baseca/internal/validator" + "github.com/gogo/status" + "github.com/google/uuid" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + _production = "production" +) + +func (s *Service) CreateProvisionerAccount(ctx context.Context, req *apiv1.CreateProvisionerAccountRequest) (*apiv1.CreateProvisionerAccountResponse, error) { + var service *db.Provisioner + nodeAttestation := []string{} + + subject_alternative_names := validator.SanitizeInput(req.SubjectAlternativeNames) + + err := s.validateSanInputProvisionerAccount(ctx, req.ProvisionerAccount, req.Environments, req.SubjectAlternativeNames, req.RegularExpression) + if err != nil { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "provisioner subject alternative name (san) validation error"), fmt.Errorf("provisioner account subject alternative name validation error [%s]", err)) + } + + if req.MaxCertificateValidity <= 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid max_certificate_validity parameter"), fmt.Errorf("invalid max_certificate_validity parameter [%d]", req.MaxCertificateValidity)) + } + + if len(req.Environments) == 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid environments parameter"), fmt.Errorf("invalid environments parameter")) + } + + for _, environment := range req.Environments { + if _, ok := validator.CertificateAuthorityEnvironments[environment]; !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid certificate authority environment"), fmt.Errorf("invalid certificate authority environment [%s]", environment)) + } + } + + if len(req.ExtendedKeys) == 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid extended keys parameter"), fmt.Errorf("invalid extended keys parameter")) + } + + for _, extendedKey := range req.ExtendedKeys { + if _, ok := types.CertificateRequestExtension[extendedKey]; !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid extended key"), fmt.Errorf("invalid key extension [%s]", extendedKey)) + } + } + + if ok := validator.ValidateEmail(req.Email); !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid email"), fmt.Errorf("invalid email [%s]", req.Email)) + } + + if len(req.Team) == 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid team parameter"), fmt.Errorf("invalid team [%s]", req.Team)) + } + + client_id, err := uuid.NewRandom() + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + clientToken, err := authentication.GenerateClientToken(32) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + hashedClientToken, err := authentication.HashPassword(clientToken) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + payload, ok := ctx.Value(types.AuthorizationPayloadKey).(*authentication.Claims) + if !ok { + return nil, status.Error(codes.InvalidArgument, "service auth context missing") + } + + if validator.Contains(req.Environments, _production) || req.NodeAttestation != nil { + if err = validateNodeAttestation(req.NodeAttestation); err != nil { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, err.Error()), err) + } + } + + if req.NodeAttestation != nil { + nodeAttestation = aws_iid.GetNodeAttestation(req.NodeAttestation) + + account_arg := db.CreateProvisionerAccountParams{ + ClientID: client_id, + ApiToken: hashedClientToken, + ProvisionerAccount: req.ProvisionerAccount, + Environments: req.Environments, + NodeAttestation: nodeAttestation, + Team: req.Team, + Email: req.Email, + ValidSubjectAlternateNames: subject_alternative_names, + ExtendedKeys: req.ExtendedKeys, + MaxCertificateValidity: int16(req.MaxCertificateValidity), + CreatedBy: payload.Subject, + CreatedAt: time.Now().UTC(), + } + + if len(req.RegularExpression) != 0 { + account_arg.RegularExpression = sql.NullString{String: req.RegularExpression, Valid: len(req.RegularExpression) != 0} + } + + raw_message, err := validator.MapToNullRawMessage(req.NodeAttestation.AwsIid.InstanceTags) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + iid_arg := db.StoreInstanceIdentityDocumentParams{ + ClientID: client_id, + RoleArn: sql.NullString{String: req.NodeAttestation.AwsIid.RoleArn, Valid: len(req.NodeAttestation.AwsIid.RoleArn) != 0}, + AssumeRole: sql.NullString{String: req.NodeAttestation.AwsIid.AssumeRole, Valid: len(req.NodeAttestation.AwsIid.AssumeRole) != 0}, + Region: sql.NullString{String: req.NodeAttestation.AwsIid.Region, Valid: len(req.NodeAttestation.AwsIid.Region) != 0}, + InstanceID: sql.NullString{String: req.NodeAttestation.AwsIid.InstanceId, Valid: len(req.NodeAttestation.AwsIid.InstanceId) != 0}, + ImageID: sql.NullString{String: req.NodeAttestation.AwsIid.ImageId, Valid: len(req.NodeAttestation.AwsIid.ImageId) != 0}, + SecurityGroupID: req.NodeAttestation.AwsIid.SecurityGroups, + InstanceTags: raw_message, + } + + service, err = s.store.Writer.TxCreateProvisionerAccount(ctx, account_arg, iid_arg) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "error creating account"), err) + } + } else { + account_arg := db.CreateProvisionerAccountParams{ + ClientID: client_id, + ApiToken: hashedClientToken, + ProvisionerAccount: req.ProvisionerAccount, + Environments: req.Environments, + NodeAttestation: nodeAttestation, + Team: req.Team, + Email: req.Email, + ValidSubjectAlternateNames: subject_alternative_names, + ExtendedKeys: req.ExtendedKeys, + MaxCertificateValidity: int16(req.MaxCertificateValidity), + CreatedBy: payload.Subject, + CreatedAt: time.Now().UTC(), + } + + if len(req.RegularExpression) != 0 { + account_arg.RegularExpression = sql.NullString{String: req.RegularExpression, Valid: len(req.RegularExpression) != 0} + } + + service, err = s.store.Writer.CreateProvisionerAccount(ctx, account_arg) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "error creating account"), err) + } + } + + account := apiv1.CreateProvisionerAccountResponse{ + ClientId: service.ClientID.String(), + ClientToken: clientToken, + ProvisionerAccount: service.ProvisionerAccount, + Environments: service.Environments, + NodeAttestation: req.NodeAttestation, + SubjectAlternativeNames: service.ValidSubjectAlternateNames, + ExtendedKeys: service.ExtendedKeys, + MaxCertificateValidity: uint32(service.MaxCertificateValidity), + Team: service.Team, + Email: service.Email, + CreatedAt: timestamppb.New(service.CreatedAt), + CreatedBy: service.CreatedBy.String(), + } + + if service.RegularExpression.Valid { + account.RegularExpression = service.RegularExpression.String + } + + return &account, nil +} + +func (s *Service) DeleteProvisionAccount(ctx context.Context, req *apiv1.AccountId) (*emptypb.Empty, error) { + client_id, err := uuid.Parse(req.Uuid) + if err != nil { + return &emptypb.Empty{}, logger.RpcError(status.Error(codes.InvalidArgument, "invalid uuid format"), err) + } + + err = s.store.Writer.TxDeleteProvisionerAccount(ctx, client_id) + if err != nil { + return &emptypb.Empty{}, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + return &emptypb.Empty{}, nil +} + +func (s *Service) ProvisionServiceAccount(ctx context.Context, req *apiv1.ProvisionServiceAccountRequest) (*apiv1.ProvisionServiceAccountResponse, error) { + var service *db.Account + + nodeAttestation := []string{} + certAuth := []string{} + + subject_alternative_names := validator.SanitizeInput(req.SubjectAlternativeNames) + certificate_authorities := validator.SanitizeInput(req.CertificateAuthorities) + + payload, ok := ctx.Value(types.ClientAuthorizationPayload).(*authentication.ProvisionerAccountPayload) + if !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "service auth context missing"), fmt.Errorf("service auth context missing")) + } + + if !validator.Contains(payload.Environments, req.Environment) { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid environment"), fmt.Errorf("invalid environment [%s]", req.Environment)) + } + + err := s.validateSanInputServiceAccount(ctx, req.ServiceAccount, req.Environment, req.SubjectAlternativeNames, &req.RegularExpression) + if err != nil { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "provisioner subject alternative name (san) validation error"), fmt.Errorf("provisioner subject alternative name validation error [%s]", err)) + } + + regex, err := regexp.Compile(payload.RegularExpression) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + for _, reqSan := range req.SubjectAlternativeNames { + if !validator.Contains(payload.ValidSubjectAlternateNames, reqSan) && !regex.Match([]byte(reqSan)) { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "internal server error"), fmt.Errorf("subject alternative name (san) %s exists in another provisioner account", reqSan)) + } + } + + if len(certificate_authorities) == 0 { + certAuth = append(certAuth, validator.CertificateAuthorityEnvironments[req.Environment]...) + } else { + certAuth = req.CertificateAuthorities + } + + if !validator.Contains(payload.Environments, req.Environment) { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid extended key"), fmt.Errorf("invalid environment [%s]", req.Environment)) + } + + err = s.validateCertificateParameters(certAuth, req.Environment, int16(req.CertificateValidity), req.SubordinateCa) + if err != nil { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, err.Error()), err) + } + + if _, ok := types.CertificateRequestExtension[req.ExtendedKey]; !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid extended key"), fmt.Errorf("invalid key extension [%s]", req.ExtendedKey)) + } + + if !validator.Contains(payload.ExtendedKeys, req.ExtendedKey) && !validator.Contains(payload.ExtendedKeys, "*") { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid extended key"), fmt.Errorf("invalid key extension [%s]", req.ExtendedKey)) + } + + if ok := validator.ValidateEmail(req.Email); !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid email"), fmt.Errorf("invalid email [%s]", req.Email)) + } + + if len(req.Team) == 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid team parameter"), fmt.Errorf("invalid team [%s]", req.Team)) + } + + if req.Environment == _production || req.NodeAttestation != nil { + if err = validateNodeAttestation(req.NodeAttestation); err != nil { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, err.Error()), err) + } + } + + client_id, err := uuid.NewRandom() + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + clientToken, err := authentication.GenerateClientToken(32) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + hashedClientToken, err := authentication.HashPassword(clientToken) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + if req.NodeAttestation != nil { + nodeAttestation = aws_iid.GetNodeAttestation(req.NodeAttestation) + + account_arg := db.CreateServiceAccountParams{ + ClientID: client_id, + ApiToken: hashedClientToken, + ServiceAccount: req.ServiceAccount, + Environment: req.Environment, + NodeAttestation: nodeAttestation, + Team: req.Team, + Email: req.Email, + ValidSubjectAlternateName: subject_alternative_names, + ValidCertificateAuthorities: certAuth, + ExtendedKey: req.ExtendedKey, + CertificateValidity: int16(req.CertificateValidity), + SubordinateCa: req.SubordinateCa, + Provisioned: true, + CreatedBy: payload.ClientId, + CreatedAt: time.Now().UTC(), + } + + if len(req.RegularExpression) != 0 { + account_arg.RegularExpression = sql.NullString{String: req.RegularExpression, Valid: len(req.RegularExpression) != 0} + } + + raw_message, err := validator.MapToNullRawMessage(req.NodeAttestation.AwsIid.InstanceTags) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + iid_arg := db.StoreInstanceIdentityDocumentParams{ + ClientID: client_id, + RoleArn: sql.NullString{String: req.NodeAttestation.AwsIid.RoleArn, Valid: len(req.NodeAttestation.AwsIid.RoleArn) != 0}, + AssumeRole: sql.NullString{String: req.NodeAttestation.AwsIid.AssumeRole, Valid: len(req.NodeAttestation.AwsIid.AssumeRole) != 0}, + Region: sql.NullString{String: req.NodeAttestation.AwsIid.Region, Valid: len(req.NodeAttestation.AwsIid.Region) != 0}, + InstanceID: sql.NullString{String: req.NodeAttestation.AwsIid.InstanceId, Valid: len(req.NodeAttestation.AwsIid.InstanceId) != 0}, + ImageID: sql.NullString{String: req.NodeAttestation.AwsIid.ImageId, Valid: len(req.NodeAttestation.AwsIid.ImageId) != 0}, + SecurityGroupID: req.NodeAttestation.AwsIid.SecurityGroups, + InstanceTags: raw_message, + } + + service, err = s.store.Writer.TxCreateServiceAccount(ctx, account_arg, iid_arg) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "error creating account"), err) + } + } else { + account_arg := db.CreateServiceAccountParams{ + ClientID: client_id, + ApiToken: hashedClientToken, + ServiceAccount: req.ServiceAccount, + Environment: req.Environment, + NodeAttestation: nodeAttestation, + Team: req.Team, + Email: req.Email, + ValidSubjectAlternateName: subject_alternative_names, + ValidCertificateAuthorities: certAuth, + ExtendedKey: req.ExtendedKey, + CertificateValidity: int16(req.CertificateValidity), + SubordinateCa: req.SubordinateCa, + Provisioned: true, + CreatedBy: payload.ClientId, + CreatedAt: time.Now().UTC(), + } + + if len(req.RegularExpression) != 0 { + account_arg.RegularExpression = sql.NullString{String: req.RegularExpression, Valid: len(req.RegularExpression) != 0} + } + + service, err = s.store.Writer.CreateServiceAccount(ctx, account_arg) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "error creating account"), err) + } + } + + response := apiv1.ProvisionServiceAccountResponse{ + ClientId: service.ClientID.String(), + ClientToken: clientToken, + ServiceAccount: service.ServiceAccount, + Environment: service.Environment, + NodeAttestation: req.NodeAttestation, + SubjectAlternativeNames: service.ValidSubjectAlternateName, + ExtendedKey: service.ExtendedKey, + CertificateAuthorities: service.ValidCertificateAuthorities, + CertificateValidity: int32(service.CertificateValidity), + SubordinateCa: service.SubordinateCa, + Team: service.Team, + Email: service.Email, + CreatedAt: timestamppb.New(service.CreatedAt), + CreatedBy: service.CreatedBy.String(), + } + + if service.RegularExpression.Valid { + response.RegularExpression = service.RegularExpression.String + } + + return &response, nil +} diff --git a/internal/v1/accounts/provision_test.go b/internal/v1/accounts/provision_test.go new file mode 100644 index 0000000..54ef955 --- /dev/null +++ b/internal/v1/accounts/provision_test.go @@ -0,0 +1,173 @@ +package accounts + +import ( + "context" + "database/sql" + "fmt" + "reflect" + "testing" + "time" + + "github.com/coinbase/baseca/db/mock" + db "github.com/coinbase/baseca/db/sqlc" + apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" + "github.com/coinbase/baseca/internal/authentication" + "github.com/coinbase/baseca/internal/types" + "github.com/golang/mock/gomock" + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +func TestCreateProvisionerAccount(t *testing.T) { + id, err := uuid.NewRandom() + require.NoError(t, err) + + authClaim := &authentication.Claims{ + Permission: "ADMIN", + Subject: id, + IssuedAt: time.Now(), + ExpiresAt: time.Now().AddDate(0, 0, 1), + NotBefore: time.Now(), + } + + attestation := apiv1.AWSInstanceIdentityDocument{ + RoleArn: "arn:aws:iam::123456789012:instance-profile/role", + AssumeRole: "arn:aws:iam::123456789012:role/assumed-role", + SecurityGroups: []string{"sg-0123456789abcdef0"}, + Region: "us-east-1", + } + + request := &apiv1.CreateProvisionerAccountRequest{ + ProvisionerAccount: "example", + Environments: []string{"development"}, + SubjectAlternativeNames: []string{"development.example.com"}, + ExtendedKeys: []string{"EndEntityServerAuthCertificate"}, + MaxCertificateValidity: 30, + Team: "Team", + Email: "example@coinbase.com", + } + + requestOK := &apiv1.CreateProvisionerAccountRequest{ + ProvisionerAccount: "example", + Environments: []string{"development"}, + SubjectAlternativeNames: []string{"development.example.com"}, + ExtendedKeys: []string{"EndEntityServerAuthCertificate"}, + MaxCertificateValidity: 30, + NodeAttestation: &apiv1.NodeAttestation{ + AwsIid: &attestation, + }, + Team: "Team", + Email: "example@coinbase.com", + } + + cases := []struct { + name string + req *apiv1.CreateProvisionerAccountRequest + ctx context.Context + build func(store *mock.MockStore) + check func(t *testing.T, res *apiv1.CreateProvisionerAccountResponse, err error) + }{ + { + name: "OK_NO_ATTESTATION", + req: request, + ctx: context.WithValue(context.Background(), types.AuthorizationPayloadKey, authClaim), + build: func(store *mock.MockStore) { + account_arg := db.CreateProvisionerAccountParams{ + ProvisionerAccount: "example", + Environments: []string{"development"}, + ValidSubjectAlternateNames: []string{"development.example.com"}, + ExtendedKeys: []string{"EndEntityServerAuthCertificate"}, + MaxCertificateValidity: 30, + Team: "Team", + Email: "example@coinbase.com", + CreatedBy: authClaim.Subject, + NodeAttestation: []string{}, + } + store.EXPECT().ListProvisionerAccounts(gomock.Any(), gomock.Any()).Times(1).Return([]*db.Provisioner{}, nil) + store.EXPECT().CreateProvisionerAccount(gomock.Any(), + EqCreateProvisionerAccountParams(account_arg, "provisioner arg matcher")).Times(1).Return(&db.Provisioner{}, nil) + }, + check: func(t *testing.T, res *apiv1.CreateProvisionerAccountResponse, err error) { + require.NoError(t, err) + }, + }, + { + name: "OK", + req: requestOK, + ctx: context.WithValue(context.Background(), types.AuthorizationPayloadKey, authClaim), + build: func(store *mock.MockStore) { + account_arg := db.CreateProvisionerAccountParams{ + ProvisionerAccount: "example", + Environments: []string{"development"}, + ValidSubjectAlternateNames: []string{"development.example.com"}, + ExtendedKeys: []string{"EndEntityServerAuthCertificate"}, + MaxCertificateValidity: 30, + Team: "Team", + Email: "example@coinbase.com", + CreatedBy: authClaim.Subject, + NodeAttestation: []string{"AWS_IID"}, + } + + attestation_arg := db.StoreInstanceIdentityDocumentParams{ + RoleArn: sql.NullString{String: attestation.RoleArn, Valid: true}, + AssumeRole: sql.NullString{String: attestation.AssumeRole, Valid: true}, + SecurityGroupID: attestation.SecurityGroups, + Region: sql.NullString{String: attestation.Region, Valid: true}, + } + + store.EXPECT().ListProvisionerAccounts(gomock.Any(), gomock.Any()).Times(1).Return([]*db.Provisioner{}, nil) + store.EXPECT().TxCreateProvisionerAccount(gomock.Any(), + EqCreateProvisionerAccountParams(account_arg, "provisioner arg matcher"), + EqStoreInstanceIdentityDocumentParams(attestation_arg, "iid arg matcher"), + ).Times(1).Return(&db.Provisioner{}, nil) + }, + check: func(t *testing.T, res *apiv1.CreateProvisionerAccountResponse, err error) { + require.NoError(t, err) + }, + }, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + store := mock.NewMockStore(ctrl) + + for elem := range cases { + tc := cases[elem] + + t.Run(tc.name, func(t *testing.T) { + tc.build(store) + + c, err := buildAccountsConfig(store) + require.NoError(t, err) + + res, err := c.CreateProvisionerAccount(tc.ctx, tc.req) + tc.check(t, res, err) + }) + } +} + +type eqCreateProvisionerProvisionerParamsMatcher struct { + arg db.CreateProvisionerAccountParams + password string +} + +func (e eqCreateProvisionerProvisionerParamsMatcher) Matches(x interface{}) bool { + arg, ok := x.(db.CreateProvisionerAccountParams) + if !ok { + return false + } + + e.arg.ClientID = arg.ClientID + e.arg.ApiToken = arg.ApiToken + e.arg.CreatedAt = arg.CreatedAt + return reflect.DeepEqual(e.arg, arg) +} + +func (e eqCreateProvisionerProvisionerParamsMatcher) String() string { + return fmt.Sprintf("%v", e.arg) +} + +func EqCreateProvisionerAccountParams(arg db.CreateProvisionerAccountParams, password string) gomock.Matcher { + return eqCreateProvisionerProvisionerParamsMatcher{arg, password} +} diff --git a/internal/v1/accounts/query.go b/internal/v1/accounts/query.go index e90b453..9e0dd03 100644 --- a/internal/v1/accounts/query.go +++ b/internal/v1/accounts/query.go @@ -34,7 +34,7 @@ func (s *Service) ListServiceAccounts(ctx context.Context, req *apiv1.QueryParam } for _, service := range services { - account, err := s.accountQuery(ctx, service) + account, err := s.transformServiceAccount(ctx, service) if err != nil { return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) } @@ -44,7 +44,34 @@ func (s *Service) ListServiceAccounts(ctx context.Context, req *apiv1.QueryParam return &accounts, nil } -func (s *Service) GetServiceAccountUuid(ctx context.Context, req *apiv1.ServiceAccountId) (*apiv1.ServiceAccount, error) { +func (s *Service) ListProvisionerAccounts(ctx context.Context, req *apiv1.QueryParameter) (*apiv1.ProvisionerAccounts, error) { + var accounts apiv1.ProvisionerAccounts + + if req.PageId <= 0 || req.PageSize <= 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid request parameters"), fmt.Errorf("invalid page_id or page_size")) + } + + arg := db.ListProvisionerAccountsParams{ + Limit: req.PageSize, + Offset: (req.PageId - 1) * req.PageSize, + } + + provisioners, err := s.store.Reader.ListProvisionerAccounts(ctx, arg) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + for _, provisioner := range provisioners { + account, err := s.transformProvisionerAccount(ctx, provisioner) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + accounts.ProvisionerAccounts = append(accounts.ProvisionerAccounts, account) + } + return &accounts, nil +} + +func (s *Service) GetServiceAccount(ctx context.Context, req *apiv1.AccountId) (*apiv1.ServiceAccount, error) { id, err := uuid.Parse(req.Uuid) if err != nil { return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid uuid parameter"), err) @@ -58,7 +85,29 @@ func (s *Service) GetServiceAccountUuid(ctx context.Context, req *apiv1.ServiceA return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) } - account, err := s.accountQuery(ctx, service) + account, err := s.transformServiceAccount(ctx, service) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + return account, nil +} + +func (s *Service) GetProvisionerAccount(ctx context.Context, req *apiv1.AccountId) (*apiv1.ProvisionerAccount, error) { + id, err := uuid.Parse(req.Uuid) + if err != nil { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid uuid parameter"), err) + } + + provisioner, err := s.store.Reader.GetProvisionerUUID(ctx, id) + if err != nil { + if err == sql.ErrNoRows { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("provisioner account uuid %s does not exist", id)) + } + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + account, err := s.transformProvisionerAccount(ctx, provisioner) if err != nil { return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) } @@ -66,7 +115,7 @@ func (s *Service) GetServiceAccountUuid(ctx context.Context, req *apiv1.ServiceA return account, nil } -func (s *Service) accountQuery(ctx context.Context, account *db.Account) (*apiv1.ServiceAccount, error) { +func (s *Service) transformServiceAccount(ctx context.Context, account *db.Account) (*apiv1.ServiceAccount, error) { var attestation types.NodeAttestation if validator.Contains(account.NodeAttestation, types.Attestation.AWS_IID) { @@ -103,6 +152,8 @@ func (s *Service) accountQuery(ctx context.Context, account *db.Account) (*apiv1 CertificateAuthorities: account.ValidCertificateAuthorities, ExtendedKey: account.ExtendedKey, CertificateValidity: int32(account.CertificateValidity), + SubordinateCa: account.SubordinateCa, + Provisioned: account.Provisioned, Team: account.Team, Email: account.Email, CreatedAt: timestamppb.New(account.CreatedAt), @@ -120,21 +171,104 @@ func (s *Service) accountQuery(ctx context.Context, account *db.Account) (*apiv1 }, nil } -func (s *Service) GetServiceAccountName(ctx context.Context, req *apiv1.ServiceAccountName) (*apiv1.ServiceAccounts, error) { +func (s *Service) transformProvisionerAccount(ctx context.Context, account *db.Provisioner) (*apiv1.ProvisionerAccount, error) { + var attestation types.NodeAttestation + + if validator.Contains(account.NodeAttestation, types.Attestation.AWS_IID) { + iid, err := s.store.Reader.GetInstanceIdentityDocument(ctx, account.ClientID) + if err != nil { + return nil, err + } + + instance_tag_map, err := validator.ConvertNullRawMessageToMap(iid.InstanceTags) + if err != nil { + return nil, err + } + + // TODO: Update awsIid {} Response + attestation = types.NodeAttestation{ + AWSInstanceIdentityDocument: types.AWSInstanceIdentityDocument{ + RoleArn: iid.RoleArn.String, + AssumeRole: iid.AssumeRole.String, + SecurityGroups: iid.SecurityGroupID, + Region: iid.Region.String, + InstanceID: iid.InstanceID.String, + ImageID: iid.ImageID.String, + InstanceTags: instance_tag_map, + }, + } + } + + return &apiv1.ProvisionerAccount{ + ClientId: account.ClientID.String(), + ProvisionerAccount: account.ProvisionerAccount, + Environments: account.Environments, + RegularExpression: account.RegularExpression.String, + SubjectAlternativeNames: account.ValidSubjectAlternateNames, + ExtendedKeys: account.ExtendedKeys, + MaxCertificateValidity: uint32(account.MaxCertificateValidity), + Team: account.Team, + Email: account.Email, + CreatedAt: timestamppb.New(account.CreatedAt), + CreatedBy: account.CreatedBy.String(), + NodeAttestation: &apiv1.NodeAttestation{ + AwsIid: &apiv1.AWSInstanceIdentityDocument{ + RoleArn: attestation.AWSInstanceIdentityDocument.RoleArn, + AssumeRole: attestation.AWSInstanceIdentityDocument.AssumeRole, + SecurityGroups: attestation.AWSInstanceIdentityDocument.SecurityGroups, + Region: attestation.AWSInstanceIdentityDocument.Region, + InstanceId: attestation.AWSInstanceIdentityDocument.InstanceID, + InstanceTags: attestation.AWSInstanceIdentityDocument.InstanceTags, + }, + }, + }, nil +} + +func (s *Service) GetServiceAccountMetadata(ctx context.Context, req *apiv1.GetServiceAccountMetadataRequest) (*apiv1.ServiceAccounts, error) { var accounts apiv1.ServiceAccounts - account_name := req.ServiceAccount + var serviceAccount, environment, extendedKey string + + if len(req.ServiceAccount) == 0 && len(req.Environment) == 0 && len(req.ExtendedKey) == 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid parameters"), fmt.Errorf("invalid parameters nil or empty")) + } if len(req.ServiceAccount) == 0 { - return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid service_account parameter"), fmt.Errorf("invalid service_account parameter")) + serviceAccount = "%" + } else { + serviceAccount = req.ServiceAccount + } + + if len(req.Environment) == 0 { + environment = "%" + } else { + if !validator.ValidateInput(req.Environment) { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid parameters"), fmt.Errorf("invalid environment: %s", req.ServiceAccount)) + } + environment = req.Environment } - service_accounts, err := s.store.Reader.GetServiceAccounts(ctx, account_name) + if len(req.ExtendedKey) == 0 { + extendedKey = "%" + } else { + if !validator.ValidateInput(req.ExtendedKey) { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid parameters"), fmt.Errorf("invalid extended key: %s", req.ExtendedKey)) + } + extendedKey = req.ExtendedKey + } + + arg := db.GetServiceAccountByMetadataParams{ + ServiceAccount: serviceAccount, + Environment: environment, + ExtendedKey: extendedKey, + } + + services, err := s.store.Reader.GetServiceAccountByMetadata(ctx, arg) if err != nil { return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) } - for _, service_account := range service_accounts { - account, err := s.accountQuery(ctx, service_account) + for _, service := range services { + account, err := s.transformServiceAccount(ctx, service) if err != nil { return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) } diff --git a/internal/v1/accounts/query_test.go b/internal/v1/accounts/query_test.go index ebb5089..c3f78c0 100644 --- a/internal/v1/accounts/query_test.go +++ b/internal/v1/accounts/query_test.go @@ -144,13 +144,13 @@ func TestGetServiceAccount(t *testing.T) { cases := []struct { name string - req *apiv1.ServiceAccountId + req *apiv1.AccountId build func(store *mock.MockStore) check func(t *testing.T, res *apiv1.ServiceAccount, err error) }{ { name: "OK_NO_ATTESTATION", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: clientId.String(), }, build: func(store *mock.MockStore) { @@ -162,16 +162,16 @@ func TestGetServiceAccount(t *testing.T) { }, { name: "OK", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: clientId.String(), }, build: func(store *mock.MockStore) { - account := db.Account{ + account := &db.Account{ ClientID: clientId, NodeAttestation: []string{"AWS_IID"}, } - store.EXPECT().GetServiceUUID(gomock.Any(), clientId).Times(1).Return(&account, nil) + store.EXPECT().GetServiceUUID(gomock.Any(), clientId).Times(1).Return(account, nil) store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(&db.AwsAttestation{}, nil) }, check: func(t *testing.T, res *apiv1.ServiceAccount, err error) { @@ -181,7 +181,7 @@ func TestGetServiceAccount(t *testing.T) { }, { name: "DB_ERROR_GET_SERVICE_UUID", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: clientId.String(), }, build: func(store *mock.MockStore) { @@ -195,15 +195,15 @@ func TestGetServiceAccount(t *testing.T) { }, { name: "DB_ERROR_GET_INSTANCE_IDENTITY_DOCUMENT", - req: &apiv1.ServiceAccountId{ + req: &apiv1.AccountId{ Uuid: clientId.String(), }, build: func(store *mock.MockStore) { - account := db.Account{ + account := &db.Account{ ClientID: clientId, NodeAttestation: []string{"AWS_IID"}, } - store.EXPECT().GetServiceUUID(gomock.Any(), clientId).Times(1).Return(&account, nil) + store.EXPECT().GetServiceUUID(gomock.Any(), clientId).Times(1).Return(account, nil) store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(nil, fmt.Errorf("get instance identity document")) }, check: func(t *testing.T, res *apiv1.ServiceAccount, err error) { @@ -228,23 +228,35 @@ func TestGetServiceAccount(t *testing.T) { c, err := buildAccountsConfig(store) require.NoError(t, err) - res, err := c.GetServiceAccountUuid(context.Background(), tc.req) + res, err := c.GetServiceAccount(context.Background(), tc.req) tc.check(t, res, err) }) } } -func TestGetServiceAccountByName(t *testing.T) { +func TestGetServiceAccountByMetadata(t *testing.T) { account_name := "example" - request := &apiv1.ServiceAccountName{ + environment := "development" + extended_key := "EndEntityServerAuthCertificate" + + request := &apiv1.GetServiceAccountMetadataRequest{ + ServiceAccount: account_name, + Environment: environment, + ExtendedKey: extended_key, + } + + arg := db.GetServiceAccountByMetadataParams{ ServiceAccount: account_name, + Environment: environment, + ExtendedKey: extended_key, } + clientId, err := uuid.NewRandom() require.NoError(t, err) cases := []struct { name string - req *apiv1.ServiceAccountName + req *apiv1.GetServiceAccountMetadataRequest build func(store *mock.MockStore) check func(t *testing.T, res *apiv1.ServiceAccounts, err error) }{ @@ -252,7 +264,7 @@ func TestGetServiceAccountByName(t *testing.T) { name: "OK_NO_SERVICE_ACCOUNT", req: request, build: func(store *mock.MockStore) { - store.EXPECT().GetServiceAccounts(gomock.Any(), account_name).Times(1).Return([]*db.Account{}, nil) + store.EXPECT().GetServiceAccountByMetadata(gomock.Any(), arg).Times(1).Return([]*db.Account{}, nil) }, check: func(t *testing.T, res *apiv1.ServiceAccounts, err error) { require.NoError(t, err) @@ -266,7 +278,7 @@ func TestGetServiceAccountByName(t *testing.T) { ServiceAccount: account_name, ClientID: clientId, } - store.EXPECT().GetServiceAccounts(gomock.Any(), account_name).Times(1).Return([]*db.Account{&account}, nil) + store.EXPECT().GetServiceAccountByMetadata(gomock.Any(), arg).Times(1).Return([]*db.Account{&account}, nil) }, check: func(t *testing.T, res *apiv1.ServiceAccounts, err error) { require.NoError(t, err) @@ -281,7 +293,7 @@ func TestGetServiceAccountByName(t *testing.T) { ClientID: clientId, NodeAttestation: []string{"AWS_IID"}, } - store.EXPECT().GetServiceAccounts(gomock.Any(), account_name).Times(1).Return([]*db.Account{&account}, nil) + store.EXPECT().GetServiceAccountByMetadata(gomock.Any(), arg).Times(1).Return([]*db.Account{&account}, nil) store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(&db.AwsAttestation{}, nil) }, check: func(t *testing.T, res *apiv1.ServiceAccounts, err error) { @@ -292,7 +304,7 @@ func TestGetServiceAccountByName(t *testing.T) { name: "DB_ERROR_GET_SERVICE_ACCOUNTS", req: request, build: func(store *mock.MockStore) { - store.EXPECT().GetServiceAccounts(gomock.Any(), account_name).Times(1).Return(nil, fmt.Errorf("get service accounts error")) + store.EXPECT().GetServiceAccountByMetadata(gomock.Any(), arg).Times(1).Return(nil, fmt.Errorf("get service accounts error")) }, check: func(t *testing.T, res *apiv1.ServiceAccounts, err error) { require.Error(t, err) @@ -309,7 +321,7 @@ func TestGetServiceAccountByName(t *testing.T) { ClientID: clientId, NodeAttestation: []string{"AWS_IID"}, } - store.EXPECT().GetServiceAccounts(gomock.Any(), account_name).Times(1).Return([]*db.Account{&account}, nil) + store.EXPECT().GetServiceAccountByMetadata(gomock.Any(), arg).Times(1).Return([]*db.Account{&account}, nil) store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(nil, fmt.Errorf("get instance identity document err")) }, check: func(t *testing.T, res *apiv1.ServiceAccounts, err error) { @@ -333,7 +345,228 @@ func TestGetServiceAccountByName(t *testing.T) { c, err := buildAccountsConfig(store) require.NoError(t, err) - res, err := c.GetServiceAccountName(context.Background(), tc.req) + res, err := c.GetServiceAccountMetadata(context.Background(), tc.req) + tc.check(t, res, err) + }) + } +} + +func TestListProvisionerAccounts(t *testing.T) { + const ( + pageId = 1 + pageSize = 5 + ) + + param := db.ListProvisionerAccountsParams{ + Limit: pageSize, + Offset: (pageId - 1) * pageSize, + } + + clientId, err := uuid.NewRandom() + require.NoError(t, err) + + cases := []struct { + name string + req *apiv1.QueryParameter + build func(store *mock.MockStore) + check func(t *testing.T, res *apiv1.ProvisionerAccounts, err error) + }{ + { + name: "OK_NO_PROVISIONER_ACCOUNT", + req: &apiv1.QueryParameter{ + PageId: 1, + PageSize: 5, + }, + build: func(store *mock.MockStore) { + store.EXPECT().ListProvisionerAccounts(gomock.Any(), param).Times(1).Return([]*db.Provisioner{}, nil) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccounts, err error) { + require.NoError(t, err) + }, + }, + { + name: "OK_NO_NODE_ATTESTATION", + req: &apiv1.QueryParameter{ + PageId: 1, + PageSize: 5, + }, + build: func(store *mock.MockStore) { + account := db.Provisioner{ + ClientID: clientId, + NodeAttestation: []string{}, + } + store.EXPECT().ListProvisionerAccounts(gomock.Any(), param).Times(1).Return([]*db.Provisioner{&account}, nil) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccounts, err error) { + require.NoError(t, err) + }, + }, + { + name: "OK", + req: &apiv1.QueryParameter{ + PageId: 1, + PageSize: 5, + }, + build: func(store *mock.MockStore) { + account := db.Provisioner{ + ClientID: clientId, + NodeAttestation: []string{"AWS_IID"}, + } + store.EXPECT().ListProvisionerAccounts(gomock.Any(), param).Times(1).Return([]*db.Provisioner{&account}, nil) + store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(&db.AwsAttestation{}, nil) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccounts, err error) { + require.NoError(t, err) + }, + }, + { + name: "DB_ERROR_LIST_PROVISIONER_ACCOUNT", + req: &apiv1.QueryParameter{ + PageId: 1, + PageSize: 5, + }, + build: func(store *mock.MockStore) { + store.EXPECT().ListProvisionerAccounts(gomock.Any(), param).Times(1).Return(nil, fmt.Errorf("list provisioner account error")) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccounts, err error) { + require.Error(t, err) + require.Empty(t, res) + require.EqualError(t, err, "rpc error: code = Internal desc = internal server error") + }, + }, + { + name: "DB_ERROR_GET_INSTANCE_IDENTITY_DOCUMENT", + req: &apiv1.QueryParameter{ + PageId: 1, + PageSize: 5, + }, + build: func(store *mock.MockStore) { + account := db.Provisioner{ + ClientID: clientId, + NodeAttestation: []string{"AWS_IID"}, + } + store.EXPECT().ListProvisionerAccounts(gomock.Any(), param).Times(1).Return([]*db.Provisioner{&account}, nil) + store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(nil, fmt.Errorf("get instance identity document error")) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccounts, err error) { + require.Error(t, err) + require.Empty(t, res) + require.EqualError(t, err, "rpc error: code = Internal desc = internal server error") + }, + }, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + store := mock.NewMockStore(ctrl) + + for elem := range cases { + tc := cases[elem] + + t.Run(tc.name, func(t *testing.T) { + tc.build(store) + + c, err := buildAccountsConfig(store) + require.NoError(t, err) + + res, err := c.ListProvisionerAccounts(context.Background(), tc.req) + tc.check(t, res, err) + }) + } +} + +func TestGetProvisionerAccount(t *testing.T) { + clientId, err := uuid.NewRandom() + require.NoError(t, err) + + cases := []struct { + name string + req *apiv1.AccountId + build func(store *mock.MockStore) + check func(t *testing.T, res *apiv1.ProvisionerAccount, err error) + }{ + { + name: "OK_NO_ATTESTATION", + req: &apiv1.AccountId{ + Uuid: clientId.String(), + }, + build: func(store *mock.MockStore) { + store.EXPECT().GetProvisionerUUID(gomock.Any(), clientId).Times(1).Return(&db.Provisioner{}, nil) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccount, err error) { + require.NoError(t, err) + }, + }, + { + name: "OK", + req: &apiv1.AccountId{ + Uuid: clientId.String(), + }, + build: func(store *mock.MockStore) { + account := &db.Provisioner{ + ClientID: clientId, + NodeAttestation: []string{"AWS_IID"}, + } + + store.EXPECT().GetProvisionerUUID(gomock.Any(), clientId).Times(1).Return(account, nil) + store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(&db.AwsAttestation{}, nil) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccount, err error) { + require.NoError(t, err) + require.NotEmpty(t, res) + }, + }, + { + name: "DB_ERROR_GET_SERVICE_UUID", + req: &apiv1.AccountId{ + Uuid: clientId.String(), + }, + build: func(store *mock.MockStore) { + store.EXPECT().GetProvisionerUUID(gomock.Any(), clientId).Times(1).Return(nil, fmt.Errorf("get service uuid error")) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccount, err error) { + require.Error(t, err) + require.EqualError(t, err, "rpc error: code = Internal desc = internal server error") + require.Empty(t, res) + }, + }, + { + name: "DB_ERROR_GET_INSTANCE_IDENTITY_DOCUMENT", + req: &apiv1.AccountId{ + Uuid: clientId.String(), + }, + build: func(store *mock.MockStore) { + account := &db.Provisioner{ + ClientID: clientId, + NodeAttestation: []string{"AWS_IID"}, + } + store.EXPECT().GetProvisionerUUID(gomock.Any(), clientId).Times(1).Return(account, nil) + store.EXPECT().GetInstanceIdentityDocument(gomock.Any(), clientId).Times(1).Return(nil, fmt.Errorf("get instance identity document")) + }, + check: func(t *testing.T, res *apiv1.ProvisionerAccount, err error) { + require.Error(t, err) + require.EqualError(t, err, "rpc error: code = Internal desc = internal server error") + require.Empty(t, res) + }, + }, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + store := mock.NewMockStore(ctrl) + + for elem := range cases { + tc := cases[elem] + + t.Run(tc.name, func(t *testing.T) { + tc.build(store) + + c, err := buildAccountsConfig(store) + require.NoError(t, err) + + res, err := c.GetProvisionerAccount(context.Background(), tc.req) tc.check(t, res, err) }) } diff --git a/internal/v1/accounts/service.go b/internal/v1/accounts/service.go index b635c68..978ca16 100644 --- a/internal/v1/accounts/service.go +++ b/internal/v1/accounts/service.go @@ -32,7 +32,7 @@ func (s *Service) CreateServiceAccount(ctx context.Context, req *apiv1.CreateSer } // Validate Subject Alternate Name and Regular Expression - err = s.validateSanInput(ctx, req.ServiceAccount, req.Environment, req.SubjectAlternativeNames, req.RegularExpression) + err = s.validateSanInputServiceAccount(ctx, req.ServiceAccount, req.Environment, req.SubjectAlternativeNames, req.RegularExpression) if err != nil { return nil, logger.RpcError(status.Error(codes.InvalidArgument, err.Error()), err) } @@ -66,11 +66,11 @@ func (s *Service) CreateServiceAccount(ctx context.Context, req *apiv1.CreateSer payload, ok := ctx.Value(types.AuthorizationPayloadKey).(*authentication.Claims) if !ok { - return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("service auth context missing")) + logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("service auth context missing")) } // Production Service Accounts Require Attestation - if req.Environment == "production" { + if req.Environment == _production || req.NodeAttestation != nil { if err = validateNodeAttestation(req.NodeAttestation); err != nil { return nil, logger.RpcError(status.Error(codes.InvalidArgument, err.Error()), err) } @@ -92,12 +92,13 @@ func (s *Service) CreateServiceAccount(ctx context.Context, req *apiv1.CreateSer ExtendedKey: req.ExtendedKey, CertificateValidity: int16(req.CertificateValidity), SubordinateCa: req.SubordinateCa, + Provisioned: false, CreatedBy: payload.Subject, CreatedAt: time.Now().UTC(), } if req.RegularExpression != nil { - account_arg.RegularExpression = sql.NullString{String: *req.RegularExpression, Valid: len(*req.RegularExpression) != 0} + account_arg.RegularExpression = sql.NullString{String: *req.RegularExpression, Valid: req.RegularExpression != nil} } raw_message, err := validator.MapToNullRawMessage(req.NodeAttestation.AwsIid.InstanceTags) @@ -139,7 +140,7 @@ func (s *Service) CreateServiceAccount(ctx context.Context, req *apiv1.CreateSer } if req.RegularExpression != nil { - account_arg.RegularExpression = sql.NullString{String: *req.RegularExpression, Valid: len(*req.RegularExpression) != 0} + account_arg.RegularExpression = sql.NullString{String: *req.RegularExpression, Valid: req.RegularExpression != nil} } service, err = s.store.Writer.CreateServiceAccount(ctx, account_arg) diff --git a/internal/v1/accounts/service_test.go b/internal/v1/accounts/service_test.go index 35fed5a..3ef9cf8 100644 --- a/internal/v1/accounts/service_test.go +++ b/internal/v1/accounts/service_test.go @@ -31,7 +31,7 @@ func TestCreateServiceAccount(t *testing.T) { } attestation := apiv1.AWSInstanceIdentityDocument{ - RoleArn: "arn:aws:iam::123456789012:role/role", + RoleArn: "arn:aws:iam::123456789012:instance-profile/role", AssumeRole: "arn:aws:iam::123456789012:role/assumed-role", SecurityGroups: []string{"sg-0123456789abcdef0"}, Region: "us-east-1", @@ -40,14 +40,15 @@ func TestCreateServiceAccount(t *testing.T) { accountParam := db.CreateServiceAccountParams{ ServiceAccount: "example", Environment: "sandbox", - ValidSubjectAlternateName: []string{"development.example.com"}, + ValidSubjectAlternateName: []string{"sandbox.example.com"}, ExtendedKey: "EndEntityServerAuthCertificate", NodeAttestation: []string{"AWS_IID"}, CertificateValidity: 30, ValidCertificateAuthorities: []string{"sandbox_use1"}, SubordinateCa: "infrastructure", + Provisioned: false, Team: "Infrastructure Security", - Email: "security@example.com", + Email: "security@coinbase.com", CreatedBy: id, } @@ -61,7 +62,7 @@ func TestCreateServiceAccount(t *testing.T) { request := apiv1.CreateServiceAccountRequest{ ServiceAccount: "example", Environment: "sandbox", - SubjectAlternativeNames: []string{"development.example.com"}, + SubjectAlternativeNames: []string{"sandbox.example.com"}, ExtendedKey: "EndEntityServerAuthCertificate", NodeAttestation: &apiv1.NodeAttestation{ AwsIid: &attestation, @@ -70,7 +71,7 @@ func TestCreateServiceAccount(t *testing.T) { SubordinateCa: "infrastructure", CertificateValidity: 30, Team: "Infrastructure Security", - Email: "security@example.com", + Email: "security@coinbase.com", } cases := []struct { @@ -101,25 +102,25 @@ func TestCreateServiceAccount(t *testing.T) { req: &apiv1.CreateServiceAccountRequest{ ServiceAccount: "example", Environment: "sandbox", - SubjectAlternativeNames: []string{"development.example.com"}, + SubjectAlternativeNames: []string{"sandbox.example.com"}, ExtendedKey: "EndEntityServerAuthCertificate", CertificateAuthorities: []string{"sandbox_use1"}, SubordinateCa: "infrastructure", CertificateValidity: 30, Team: "Infrastructure Security", - Email: "security@example.com", + Email: "security@coinbase.com", }, build: func(store *mock.MockStore) { account_arg := db.CreateServiceAccountParams{ ServiceAccount: "example", Environment: "sandbox", - ValidSubjectAlternateName: []string{"development.example.com"}, + ValidSubjectAlternateName: []string{"sandbox.example.com"}, ExtendedKey: "EndEntityServerAuthCertificate", CertificateValidity: 30, ValidCertificateAuthorities: []string{"sandbox_use1"}, SubordinateCa: "infrastructure", Team: "Infrastructure Security", - Email: "security@example.com", + Email: "security@coinbase.com", CreatedBy: authClaim.Subject, NodeAttestation: []string{}, } diff --git a/internal/v1/accounts/validate.go b/internal/v1/accounts/validate.go index f5cc82e..73f1e34 100644 --- a/internal/v1/accounts/validate.go +++ b/internal/v1/accounts/validate.go @@ -11,13 +11,13 @@ import ( ) const ( - _role_regex_pattern = `^arn:aws:iam::\d{12}:role\/[a-zA-Z_0-9+=,.@-]+$` - _sg_regex_pattern = `^sg-[a-zA-Z0-9]+$` - _instance_id_pattern = `^i-[a-fA-F0-9]{8,17}$` + _role_regex_pattern = `^arn:aws:iam::\d{12}:role\/[a-zA-Z_0-9+=,.@-]+$` + _instance_profile_regex_pattern = `^arn:aws:iam::\d{12}:instance-profile/[a-zA-Z0-9+=,.@\-_/]+` + _sg_regex_pattern = `^sg-[a-zA-Z0-9]+$` + _instance_id_pattern = `^i-[a-fA-F0-9]{8,17}$` ) -// Create Service Account: Check if Same SAN Exists within Other Service Account -func (s *Service) validateSanInput(ctx context.Context, service_account string, environment string, request_san []string, pattern *string) error { +func (s *Service) validateSanInputServiceAccount(ctx context.Context, service_account string, environment string, request_san []string, pattern *string) error { var page_id = int32(1) var page_size = int32(25) var sans [][]string @@ -50,7 +50,7 @@ func (s *Service) validateSanInput(ctx context.Context, service_account string, } services, err := s.store.Reader.ListServiceAccounts(ctx, arg) if err != nil { - return fmt.Errorf("error listing service accounts during san validation") + return fmt.Errorf("error listing service accounts during san validation: %s", err) } if len(services) == 0 { break @@ -60,6 +60,7 @@ func (s *Service) validateSanInput(ctx context.Context, service_account string, if service_account == elem.ServiceAccount && environment == elem.Environment { continue } + sans = append(sans, elem.ValidSubjectAlternateName) } page_id += 1 @@ -72,7 +73,65 @@ func (s *Service) validateSanInput(ctx context.Context, service_account string, } } } + return nil +} + +func (s *Service) validateSanInputProvisionerAccount(ctx context.Context, provisioner_account string, environments []string, request_san []string, pattern string) error { + var page_id = int32(1) + var page_size = int32(25) + var sans [][]string + + if len(provisioner_account) == 0 { + return fmt.Errorf("invalid provisioner_account parameter") + } + + if len(pattern) == 0 && len(request_san) == 0 { + return fmt.Errorf("subject_alternative_names and regular_expression cannot both be empty") + } + + if len(pattern) != 0 { + _, err := regexp.Compile(pattern) + if err != nil { + return fmt.Errorf("invalid regular_expressing pattern") + } + } + + for _, fqdn := range request_san { + if !validator.IsValidateDomain(fqdn) { + return fmt.Errorf("invalid domain [%s]", fqdn) + } + } + for { + arg := db.ListProvisionerAccountsParams{ + Limit: page_size, + Offset: (page_id - 1) * page_size, + } + services, err := s.store.Reader.ListProvisionerAccounts(ctx, arg) + if err != nil { + return fmt.Errorf("error listing provisioner accounts during san validation") + } + if len(services) == 0 { + break + } + for _, elem := range services { + // Do Not Include Provisioner Account with Same Name and Environment + if provisioner_account == elem.ProvisionerAccount { + continue + } + + sans = append(sans, elem.ValidSubjectAlternateNames) + } + page_id += 1 + } + + for _, san := range sans { + for _, elem := range san { + if validator.Contains(request_san, elem) { + return fmt.Errorf("subject alternative name (san) %s exists in another provisioner account", request_san) + } + } + } return nil } @@ -95,6 +154,7 @@ func (s *Service) validateCertificateParameters(certificateAuthorities []string, return fmt.Errorf("invalid certificate_validity parameter") } + // Determine Certificate Validity Greater than CA Validity for _, certificateAuthority := range certificateAuthorities { caValidity := s.acmConfig[certificateAuthority].CaActiveDay if caValidity <= int(certificateValidity) { @@ -126,7 +186,7 @@ func validateAwsIidMetadata(iid *apiv1.AWSInstanceIdentityDocument) error { var validAttestation = false if iid.RoleArn != "" { - err = validateRegularExpression(iid.RoleArn, _role_regex_pattern) + err = validateRegularExpression(iid.RoleArn, _instance_profile_regex_pattern) if err { return fmt.Errorf("invalid aws_iid instance role arn [%s]", iid.RoleArn) } diff --git a/internal/v1/certificate/certificate_test.go b/internal/v1/certificate/certificate_test.go index d260ca5..e3c0792 100644 --- a/internal/v1/certificate/certificate_test.go +++ b/internal/v1/certificate/certificate_test.go @@ -118,9 +118,11 @@ func buildCertificateConfig(store *mock_store.MockStore) (*Certificate, error) { return nil, err } + validator.SupportedConfig(config) validator.SetBaseDirectory(config) - endpoints := db.DatabaseEndpoints{Writer: store, Reader: store} + validator.SupportedEnvironments(config) + endpoints := db.DatabaseEndpoints{Writer: store, Reader: store} redisConfig := &config.Redis mockRedis := &mockedRedisClient{} diff --git a/internal/v1/certificate/operations.go b/internal/v1/certificate/operations.go index d4efbbb..9202566 100644 --- a/internal/v1/certificate/operations.go +++ b/internal/v1/certificate/operations.go @@ -31,6 +31,9 @@ var ( "KEY_COMPROMISE", "CERTIFICATE_AUTHORITY_COMPROMISE", } + + _default_signing_algorithm = "SHA512WITHRSA" + _default_validity = 365 ) func (c *Certificate) RevokeCertificate(ctx context.Context, req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { @@ -98,32 +101,72 @@ func (c *Certificate) RevokeCertificate(ctx context.Context, req *apiv1.RevokeCe } func (c *Certificate) OperationsSignCSR(ctx context.Context, req *apiv1.OperationsSignRequest) (*apiv1.SignedCertificate, error) { + var certificateAuthorityParameters *apiv1.CertificateAuthorityParameter + if err := c.validateCsrParameters(req); err != nil { return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid certificate signing request (csr)"), err) } if _, ok := types.CertificateRequestExtension[req.ExtendedKey]; !ok { - return nil, status.Error(codes.InvalidArgument, "invalid certificate extended key") + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid certificate extended key"), fmt.Errorf("invalid certificate extended key")) } - parameters := types.CertificateParameters{ - Region: req.CertificateAuthority.Region, - CaArn: req.CertificateAuthority.CaArn, - AssumeRole: req.CertificateAuthority.AssumeRole, - RoleArn: req.CertificateAuthority.RoleArn, - Validity: int(req.CertificateAuthority.Validity), - } + // Query Account Metadata to Discover Upstream Private CA + if req.CertificateAuthority == nil { + arg := db.GetServiceAccountByMetadataParams{ + ServiceAccount: req.ServiceAccount, + Environment: req.Environment, + ExtendedKey: req.ExtendedKey, + } + serviceAccount, err := c.store.Reader.GetServiceAccountByMetadata(ctx, arg) + if err != nil { + logger.RpcError(status.Error(codes.Internal, "error issuing certificate [OperationsSignCSR]"), fmt.Errorf("error querying service account metadata [%s]: %s", req.ServiceAccount, err)) + } + + if len(serviceAccount) != 1 { + return nil, logger.RpcError(status.Error(codes.Internal, "error querying service account(s)"), fmt.Errorf("[%d] service accounts found for [%s] in environment [%s], cleanup before issuing long-lived certificate", len(serviceAccount), req.ServiceAccount, req.Environment)) + } + + accountMetadata := serviceAccount[0] + certificateAuthority := accountMetadata.ValidCertificateAuthorities[0] + certificateAuthorityParameters = &apiv1.CertificateAuthorityParameter{ + Region: c.acmConfig[certificateAuthority].Region, + CaArn: c.acmConfig[certificateAuthority].CaArn, + AssumeRole: c.acmConfig[certificateAuthority].AssumeRole, + RoleArn: c.acmConfig[certificateAuthority].RoleArn, + Validity: int32(_default_validity), + SignAlgorithm: _default_signing_algorithm, + } + } else { + expirationDate := time.Now().UTC().AddDate(0, 0, int(req.CertificateAuthority.Validity)).UTC() + if expirationDate.Before(time.Now().UTC().Add(time.Minute).UTC()) { + logger.RpcError(status.Error(codes.Internal, "invalid certificate validity"), fmt.Errorf("invalid certificate validity [%s]", req.ServiceAccount)) + } + + certificateAuthorityParameters = &apiv1.CertificateAuthorityParameter{ + Region: req.CertificateAuthority.Region, + CaArn: req.CertificateAuthority.CaArn, + AssumeRole: req.CertificateAuthority.AssumeRole, + RoleArn: req.CertificateAuthority.RoleArn, + Validity: int32(req.CertificateAuthority.Validity), + SignAlgorithm: req.CertificateAuthority.SignAlgorithm, + } + } // c.pca Mock Private CA if c.pca == nil { - client, err := acm_pca.NewPrivateCaClient(parameters) + client, err := acm_pca.NewPrivateCaClient(types.CertificateParameters{ + AssumeRole: certificateAuthorityParameters.AssumeRole, + RoleArn: certificateAuthorityParameters.RoleArn, + Region: certificateAuthorityParameters.Region, + }) if err != nil { return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid parameters for acm pca client"), err) } c.pca = client } - certificate, err := c.pca.IssueCertificateFromTemplate(req.CertificateAuthority, []byte(req.CertificateSigningRequest), types.CertificateRequestExtension[req.ExtendedKey].TemplateArn) + certificate, err := c.pca.IssueCertificateFromTemplate(certificateAuthorityParameters, []byte(req.CertificateSigningRequest), types.CertificateRequestExtension[req.ExtendedKey].TemplateArn) if err != nil { return nil, logger.RpcError(status.Error(codes.Internal, "error issuing certificate"), err) } @@ -140,9 +183,9 @@ func (c *Certificate) OperationsSignCSR(ctx context.Context, req *apiv1.Operatio ExtendedKey: req.ExtendedKey, CommonName: certificate.Subject.CommonName, SubjectAlternativeName: certificate.DNSNames, - ExpirationDate: time.Now().UTC().AddDate(0, 0, int(req.CertificateAuthority.Validity)).UTC(), - IssuedDate: time.Now().UTC(), - CertificateAuthorityArn: sql.NullString{String: req.CertificateAuthority.CaArn, Valid: len(req.CertificateAuthority.CaArn) != 0}, + ExpirationDate: certificate.NotAfter.UTC(), + IssuedDate: certificate.NotBefore.UTC(), + CertificateAuthorityArn: sql.NullString{String: certificateAuthorityParameters.CaArn, Valid: len(certificateAuthorityParameters.CaArn) != 0}, } metadata, err := c.store.Writer.LogCertificate(ctx, arg) diff --git a/internal/v1/certificate/operations_test.go b/internal/v1/certificate/operations_test.go index ae01438..dbd6009 100644 --- a/internal/v1/certificate/operations_test.go +++ b/internal/v1/certificate/operations_test.go @@ -2,12 +2,16 @@ package certificate import ( "context" + "crypto/x509" "database/sql" + "fmt" "testing" "time" "github.com/coinbase/baseca/db/mock" db "github.com/coinbase/baseca/db/sqlc" + "github.com/coinbase/baseca/internal/lib/crypto" + "github.com/coinbase/baseca/internal/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -30,11 +34,11 @@ func TestGetCertificate(t *testing.T) { build: func(store *mock.MockStore) { resp := db.Certificate{ SerialNumber: serial_number, - CommonName: "example.coinbase.com", + CommonName: "development.example.com", Account: "example", Environment: "development", ExtendedKey: "EndEntityServerAuthCertificate", - SubjectAlternativeName: []string{"example.coinbase.com"}, + SubjectAlternativeName: []string{"development.example.com"}, ExpirationDate: time.Now(), IssuedDate: time.Now().Add(24 * time.Hour), Revoked: false, @@ -67,3 +71,159 @@ func TestGetCertificate(t *testing.T) { }) } } + +func TestOperationsSignCSR(t *testing.T) { + cases := []struct { + name string + req func() *apiv1.OperationsSignRequest + build func(store *mock.MockStore) + check func(t *testing.T, res *apiv1.SignedCertificate, err error) + }{ + { + name: "OK_NO_CERTIFICATE_AUTHORITY_INPUT", + req: func() *apiv1.OperationsSignRequest { + req := types.CertificateRequest{ + CommonName: "development.example.com", + SubjectAlternateNames: []string{"development.example.com"}, + SigningAlgorithm: x509.SHA512WithRSA, + PublicKeyAlgorithm: x509.RSA, + KeySize: 2048, + } + csr, _ := crypto.GenerateCSR(req) + + return &apiv1.OperationsSignRequest{ + CertificateSigningRequest: csr.CSR.String(), + ServiceAccount: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + }, + build: func(store *mock.MockStore) { + arg := db.GetServiceAccountByMetadataParams{ + ServiceAccount: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + + resp := []*db.Account{ + { + ServiceAccount: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + ValidCertificateAuthorities: []string{"sandbox_use1"}, + }, + } + + logArg := db.LogCertificateParams{ + Account: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + + logResp := &db.Certificate{ + Account: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + + store.EXPECT().GetServiceAccountByMetadata(gomock.Any(), arg).Times(1).Return(resp, nil) + store.EXPECT().LogCertificate(gomock.Any(), &certificateLogArgMatcher{ + Account: logArg.Account, + Environment: logArg.Environment, + ExtendedKey: logArg.ExtendedKey, + }).Times(1).Return(logResp, nil) + }, + check: func(t *testing.T, res *apiv1.SignedCertificate, err error) { + require.NoError(t, err) + }, + }, + { + name: "OK_CERTIFICATE_AUTHORITY_INPUT", + req: func() *apiv1.OperationsSignRequest { + req := types.CertificateRequest{ + CommonName: "development.example.com", + SubjectAlternateNames: []string{"development.example.com"}, + SigningAlgorithm: x509.SHA512WithRSA, + PublicKeyAlgorithm: x509.RSA, + KeySize: 2048, + } + csr, _ := crypto.GenerateCSR(req) + + caParameter := &apiv1.CertificateAuthorityParameter{ + Region: "us-east-1", + CaArn: "arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + SignAlgorithm: "SHA512WITHRSA", + AssumeRole: false, + } + + return &apiv1.OperationsSignRequest{ + CertificateSigningRequest: csr.CSR.String(), + CertificateAuthority: caParameter, + ServiceAccount: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + }, + build: func(store *mock.MockStore) { + logArg := db.LogCertificateParams{ + Account: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + + logResp := &db.Certificate{ + Account: "example", + Environment: "development", + ExtendedKey: "EndEntityClientAuthCertificate", + } + + store.EXPECT().LogCertificate(gomock.Any(), &certificateLogArgMatcher{ + Account: logArg.Account, + Environment: logArg.Environment, + ExtendedKey: logArg.ExtendedKey, + }).Times(1).Return(logResp, nil) + }, + check: func(t *testing.T, res *apiv1.SignedCertificate, err error) { + require.NoError(t, err) + }, + }, + } + + for elem := range cases { + tc := cases[elem] + + t.Run(tc.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + store := mock.NewMockStore(ctrl) + tc.build(store) + + c, err := buildCertificateConfig(store) + require.NoError(t, err) + + req := tc.req() + res, err := c.OperationsSignCSR(context.Background(), req) + tc.check(t, res, err) + }) + } +} + +type certificateLogArgMatcher struct { + Account string + Environment string + ExtendedKey string +} + +func (m *certificateLogArgMatcher) Matches(x interface{}) bool { + if arg, ok := x.(db.LogCertificateParams); ok { + return arg.Account == m.Account && + arg.Environment == m.Environment + } + return false +} + +func (m *certificateLogArgMatcher) String() string { + return fmt.Sprintf("Account = %v Environment = %v ExtendedKey = %v", + m.Account, m.Environment, m.ExtendedKey) +} diff --git a/internal/v1/certificate/pca.go b/internal/v1/certificate/pca.go index d1c93aa..ce31413 100644 --- a/internal/v1/certificate/pca.go +++ b/internal/v1/certificate/pca.go @@ -78,8 +78,8 @@ func (c *Certificate) issueEndEntityCertificate(auth *authentication.ServicePayl return nil, fmt.Errorf("error parsing leaf certificate data") } - intermediate_ca := fmt.Sprintf("%s_%s", auth.SubordinateCa, auth.Environment) - certificate, chained_certificate, err := crypto.BuildCertificateChain(intermediate_ca, certificateRaw, certificateAuthorityRaw) + caPath := fmt.Sprintf("%s_%s", auth.SubordinateCa, auth.Environment) + certificate, intermediate_chain, root_chain, err := crypto.BuildCertificateChain(caPath, certificateRaw, certificateAuthorityRaw) if err != nil { return nil, err } @@ -93,6 +93,7 @@ func (c *Certificate) issueEndEntityCertificate(auth *authentication.ServicePayl IssuedDate: issuedDate, CaSerialNumber: ca_certificate.SerialNumber, CertificateAuthorityArn: ca_certificate.CertificateAuthorityArn, + Timestamp: time.Now().UTC(), } event := firehose.ForwardedEventUploadEvent{ @@ -113,8 +114,9 @@ func (c *Certificate) issueEndEntityCertificate(auth *authentication.ServicePayl } return &db.CertificateResponseData{ - Certificate: certificate.String(), - CertificateChain: chained_certificate.String(), - Metadata: certificate_data, + Certificate: certificate.String(), + IntermediateCertificateChain: intermediate_chain.String(), + RootCertificateChain: root_chain.String(), + Metadata: certificate_data, }, nil } diff --git a/internal/v1/certificate/query.go b/internal/v1/certificate/query.go index 9c89b32..ddb7b99 100644 --- a/internal/v1/certificate/query.go +++ b/internal/v1/certificate/query.go @@ -2,10 +2,14 @@ package certificate import ( "context" + "database/sql" + "fmt" db "github.com/coinbase/baseca/db/sqlc" apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" "github.com/coinbase/baseca/internal/logger" + "github.com/coinbase/baseca/internal/types" + "github.com/coinbase/baseca/internal/validator" "github.com/gogo/status" "google.golang.org/grpc/codes" "google.golang.org/protobuf/types/known/timestamppb" @@ -36,7 +40,7 @@ func (c *Certificate) ListCertificates(ctx context.Context, req *apiv1.ListCerti var pbCertificates apiv1.CertificatesParameter if len(req.CommonName) == 0 { - return nil, status.Error(codes.InvalidArgument, "missing common name (cn)") + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "missing common name (cn)"), fmt.Errorf("missing common name (cn)")) } arg := db.ListCertificateSubjectAlternativeNameParams{ @@ -63,7 +67,118 @@ func (c *Certificate) ListCertificates(ctx context.Context, req *apiv1.ListCerti Revoked: certificate.Revoked, RevokedBy: certificate.RevokedBy.String, RevokeDate: timestamppb.New(certificate.RevokeDate.Time), - CertificateAuthorityArn: certificate.CertificateAuthorityArn.String}) + CertificateAuthorityArn: certificate.CertificateAuthorityArn.String, + }) } return &pbCertificates, nil } + +func (c *Certificate) QueryCertificateMetadata(ctx context.Context, req *apiv1.QueryCertificateMetadataRequest) (*apiv1.CertificatesParameter, error) { + var serialNumber, account, environment, extendedKey string + var san []string + var pbCertificates apiv1.CertificatesParameter + + if len(req.Account) == 0 && len(req.SerialNumber) == 0 && len(req.Environment) == 0 && len(req.ExtendedKey) == 0 && len(req.SubjectAlternativeName) == 0 { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid parameters"), fmt.Errorf("invalid parameters nil or empty")) + } + + if len(req.SerialNumber) != 0 { + if !validator.ValidateInput(req.SerialNumber) { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid serial number format"), fmt.Errorf("invalid serial number: %s", req.SerialNumber)) + } + serialNumber = req.SerialNumber + } else { + serialNumber = "%" + } + + if len(req.Account) != 0 { + account = req.Account + } else { + account = "%" + } + + if len(req.Environment) != 0 { + if _, ok := validator.CertificateAuthorityEnvironments[req.Environment]; !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid environment"), fmt.Errorf("invalid environment: %s", req.Environment)) + } + + environment = req.Environment + } else { + environment = "%" + } + + if len(req.ExtendedKey) != 0 { + if _, ok := types.CertificateRequestExtension[req.ExtendedKey]; !ok { + return nil, logger.RpcError(status.Error(codes.InvalidArgument, "invalid extended key"), fmt.Errorf("invalid extended key: %s", req.ExtendedKey)) + + } + extendedKey = req.ExtendedKey + } else { + extendedKey = "%" + } + + if len(req.SubjectAlternativeName) > 1 { + san = validator.SanitizeInput(req.SubjectAlternativeName) + } + + arg := db.GetSignedCertificateByMetadataParams{ + SerialNumber: serialNumber, + Account: account, + Environment: environment, + ExtendedKey: extendedKey, + } + + certificates, err := c.store.Reader.GetSignedCertificateByMetadata(ctx, arg) + if err != nil { + if err == sql.ErrNoRows { + return nil, logger.RpcError(status.Error(codes.NotFound, "certificate not found"), err) + } + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + for _, certificate := range certificates { + if len(san) == 0 { + pbCertificates.Certificates = append(pbCertificates.Certificates, &apiv1.CertificateParameter{ + SerialNumber: certificate.SerialNumber, + Account: certificate.Account, + Environment: certificate.Environment, + ExtendedKey: certificate.ExtendedKey, + CommonName: certificate.CommonName, + SubjectAlternativeName: certificate.SubjectAlternativeName, + ExpirationDate: timestamppb.New(certificate.ExpirationDate), + IssuedDate: timestamppb.New(certificate.IssuedDate), + Revoked: certificate.Revoked, + RevokedBy: certificate.RevokedBy.String, + RevokeDate: timestamppb.New(certificate.RevokeDate.Time), + CertificateAuthorityArn: certificate.CertificateAuthorityArn.String, + }) + } else { + check := true + for _, a := range san { + if !validator.Contains(certificate.SubjectAlternativeName, a) { + check = false + break + } + } + + if check { + pbCertificates.Certificates = append(pbCertificates.Certificates, &apiv1.CertificateParameter{ + SerialNumber: certificate.SerialNumber, + Account: certificate.Account, + Environment: certificate.Environment, + ExtendedKey: certificate.ExtendedKey, + CommonName: certificate.CommonName, + SubjectAlternativeName: certificate.SubjectAlternativeName, + ExpirationDate: timestamppb.New(certificate.ExpirationDate), + IssuedDate: timestamppb.New(certificate.IssuedDate), + Revoked: certificate.Revoked, + RevokedBy: certificate.RevokedBy.String, + RevokeDate: timestamppb.New(certificate.RevokeDate.Time), + CertificateAuthorityArn: certificate.CertificateAuthorityArn.String, + }) + } + } + } + + return &pbCertificates, nil +} diff --git a/internal/v1/certificate/query_test.go b/internal/v1/certificate/query_test.go new file mode 100644 index 0000000..a7ec986 --- /dev/null +++ b/internal/v1/certificate/query_test.go @@ -0,0 +1,68 @@ +package certificate + +import ( + "context" + "testing" + + "github.com/coinbase/baseca/db/mock" + db "github.com/coinbase/baseca/db/sqlc" + apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" +) + +func TestQueryCertificateMetadata(t *testing.T) { + + cases := []struct { + name string + req *apiv1.QueryCertificateMetadataRequest + build func(store *mock.MockStore) + check func(t *testing.T, res *apiv1.CertificatesParameter, err error) + }{ + { + name: "OK", + req: &apiv1.QueryCertificateMetadataRequest{ + Account: "example", + Environment: "sandbox", + }, + build: func(store *mock.MockStore) { + arg := db.GetSignedCertificateByMetadataParams{ + SerialNumber: "%", + Account: "example", + Environment: "sandbox", + ExtendedKey: "%", + } + + resp := []*db.Certificate{ + { + Account: "example", + Environment: "sandbox", + }, + } + store.EXPECT().GetSignedCertificateByMetadata(gomock.Any(), arg).Times(1).Return(resp, nil) + }, + check: func(t *testing.T, res *apiv1.CertificatesParameter, err error) { + require.NoError(t, err) + }, + }, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + store := mock.NewMockStore(ctrl) + + for elem := range cases { + tc := cases[elem] + + t.Run(tc.name, func(t *testing.T) { + tc.build(store) + + c, err := buildCertificateConfig(store) + require.NoError(t, err) + + res, err := c.QueryCertificateMetadata(context.Background(), tc.req) + tc.check(t, res, err) + }) + } +} diff --git a/internal/v1/certificate/sign.go b/internal/v1/certificate/sign.go index 572c610..d1766d4 100644 --- a/internal/v1/certificate/sign.go +++ b/internal/v1/certificate/sign.go @@ -42,9 +42,11 @@ func (c *Certificate) SignCSR(ctx context.Context, req *apiv1.CertificateSigning } if c.redis.Limit != 0 { - err = c.rateLimit(ctx, csr) - if err != nil { - return nil, logger.RpcError(status.Error(codes.ResourceExhausted, "rate limit exceeded"), err) + if !validator.Contains(c.redis.Excluded, service.ServiceAccount) { + err = c.rateLimit(ctx, csr) + if err != nil { + return nil, logger.RpcError(status.Error(codes.ResourceExhausted, "rate limit exceeded"), err) + } } } @@ -59,8 +61,9 @@ func (c *Certificate) SignCSR(ctx context.Context, req *apiv1.CertificateSigning } return &apiv1.SignedCertificate{ - Certificate: certificate.Certificate, - CertificateChain: certificate.CertificateChain, + Certificate: certificate.Certificate, + IntermediateCertificateChain: certificate.IntermediateCertificateChain, + CertificateChain: certificate.RootCertificateChain, Metadata: &apiv1.CertificateParameter{ SerialNumber: certificate.Metadata.SerialNumber, CommonName: certificate.Metadata.CommonName, @@ -73,6 +76,7 @@ func (c *Certificate) SignCSR(ctx context.Context, req *apiv1.CertificateSigning CertificateAuthorityArn: certificate.Metadata.CertificateAuthorityArn, }, }, nil + } func (c *Certificate) requestCertificate(ctx context.Context, authPayload *authentication.ServicePayload, certificateRequest *x509.CertificateRequest) (*db.CertificateResponseData, error) { diff --git a/internal/v1/certificate/validate.go b/internal/v1/certificate/validate.go index fef3a82..96044e3 100644 --- a/internal/v1/certificate/validate.go +++ b/internal/v1/certificate/validate.go @@ -106,10 +106,6 @@ func (c *Certificate) validateCsrParameters(parameters *apiv1.OperationsSignRequ } } - expirationDate := time.Now().UTC().AddDate(0, 0, int(parameters.CertificateAuthority.Validity)).UTC() - if expirationDate.Before(time.Now().UTC().Add(time.Minute).UTC()) { - return fmt.Errorf("certificate expiration before current time utc") - } return nil } diff --git a/internal/v1/middleware/authentication.go b/internal/v1/middleware/authentication.go index 82db5c9..7c66548 100644 --- a/internal/v1/middleware/authentication.go +++ b/internal/v1/middleware/authentication.go @@ -30,13 +30,16 @@ func (m *Middleware) ServerAuthenticationInterceptor(ctx context.Context, req in var ok bool methods := map[string]string{ - "/grpc.health.v1.Health/Check": _pass_auth, - "/baseca.v1.Account/LoginUser": _pass_auth, - "/baseca.v1.Account/UpdateUserCredentials": _pass_auth, - "/baseca.v1.Certificate/SignCSR": _service_auth, - "/baseca.v1.Certificate/OperationsSignCSR": _provisioner_auth, - "/baseca.v1.Service/ProvisionServiceAccount": _provisioner_auth, - "/baseca.v1.Accounts/CreateUser": _pass_auth, // Temporarily Bypass Authentication + "/grpc.health.v1.Health/Check": _pass_auth, + "/baseca.v1.Account/LoginUser": _pass_auth, + "/baseca.v1.Account/UpdateUserCredentials": _pass_auth, + "/baseca.v1.Certificate/SignCSR": _service_auth, + "/baseca.v1.Certificate/OperationsSignCSR": _provisioner_auth, + "/baseca.v1.Certificate/QueryCertificateMetadata": _provisioner_auth, + "/baseca.v1.Certificate/GetSignedIntermediateCertificate": _provisioner_auth, + "/baseca.v1.Service/ProvisionServiceAccount": _provisioner_auth, + "/baseca.v1.Service/GetServiceAccountByMetadata": _provisioner_auth, + "/baseca.v1.Service/DeleteProvisionedServiceAccount": _provisioner_auth, } if auth, ok = methods[info.FullMethod]; !ok { @@ -75,7 +78,6 @@ func (m *Middleware) ServerAuthenticationInterceptor(ctx context.Context, req in if !ok { return nil, logger.RpcError(status.Error(codes.Unauthenticated, "authentication failed"), fmt.Errorf("invalid permission error %s", userPermission)) } - ctx = context.WithValue(ctx, types.AuthorizationPayloadKey, payload) } } else if auth == _service_auth { @@ -86,7 +88,7 @@ func (m *Middleware) ServerAuthenticationInterceptor(ctx context.Context, req in ctx = context.WithValue(ctx, types.ClientAuthorizationPayload, service) } else if auth == _provisioner_auth { - service, err := m.AuthenticateServiceAccount(ctx) + service, err := m.AuthenticateProvisionerAccount(ctx) if err != nil { return nil, err } @@ -117,7 +119,7 @@ func (m *Middleware) AuthenticateServiceAccount(ctx context.Context) (*authentic return nil, status.Errorf(codes.InvalidArgument, "invalid authorization header") } - cachedServiceAccount, err := m.authenticationCache(ctx, client_uuid) + cachedServiceAccount, err := m.authenticationCacheServiceAccount(ctx, client_uuid) if err != nil { return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) } @@ -158,7 +160,67 @@ func (m *Middleware) AuthenticateServiceAccount(ctx context.Context) (*authentic return service, nil } -func (m *Middleware) authenticationCache(ctx context.Context, client_uuid uuid.UUID) (*db.CachedServiceAccount, error) { +func (m *Middleware) AuthenticateProvisionerAccount(ctx context.Context) (*authentication.ProvisionerAccountPayload, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, status.Errorf(codes.Internal, "failed to retrieve metadata from context") + } + + clientIdAuthorizationHeader, ok := md[clientIdAuthorizationHeaderKey] + if !ok { + return nil, status.Errorf(codes.InvalidArgument, "authorization header not provided") + } + + clientTokenAuthorizationHeader, ok := md[clientTokenAuthorizationHeaderKey] + if !ok { + return nil, status.Errorf(codes.InvalidArgument, "authorization header not provided") + } + + client_uuid, err := uuid.Parse(clientIdAuthorizationHeader[0]) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid authorization header") + } + + cachedProvisionerAccount, err := m.authenticationCacheProvisionerAccount(ctx, client_uuid) + if err != nil { + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), err) + } + + account := cachedProvisionerAccount.ProvisionerAccount + if err := authentication.CheckPassword(clientTokenAuthorizationHeader[0], account.ApiToken); err != nil { + return nil, logger.RpcError(status.Error(codes.Unauthenticated, "authentication error"), err) + } + + for _, node_attestation := range account.NodeAttestation { + clientIdentityDocumentHeader, ok := md[clientIdentityDocumentHeaderKey] + if !ok { + return nil, status.Errorf(codes.InvalidArgument, "authorization header not provided") + } + + switch node_attestation { + case "AWS_IID": + // Compare Signed Node Data with Attestation Table in Database + attestation_err := aws_iid.AWSIidNodeAttestation(client_uuid, clientIdentityDocumentHeader[0], cachedProvisionerAccount.AwsIid, m.cache) + if attestation_err != nil { + return nil, logger.RpcError(status.Error(codes.Unauthenticated, "aws_iid attestation error"), err) + } + } + } + + service := &authentication.ProvisionerAccountPayload{ + ClientId: account.ClientID, + ProvisionerAccount: account.ProvisionerAccount, + Environments: account.Environments, + ValidSubjectAlternateNames: account.ValidSubjectAlternateNames, + MaxCertificateValidity: uint32(account.MaxCertificateValidity), + ExtendedKeys: account.ExtendedKeys, + RegularExpression: validator.NullStringToString(&account.RegularExpression), + } + + return service, nil +} + +func (m *Middleware) authenticationCacheServiceAccount(ctx context.Context, client_uuid uuid.UUID) (*db.CachedServiceAccount, error) { var service_account *db.Account var instance_identity_document *db.AwsAttestation var cached_service_account db.CachedServiceAccount @@ -176,6 +238,7 @@ func (m *Middleware) authenticationCache(ctx context.Context, client_uuid uuid.U if err != nil { return &cached_service_account, fmt.Errorf("service authentication failed: %s", err) } + cached_service_account.ServiceAccount = *service_account for _, node_attestation := range service_account.NodeAttestation { switch node_attestation { @@ -199,3 +262,46 @@ func (m *Middleware) authenticationCache(ctx context.Context, client_uuid uuid.U } return &cached_service_account, nil } + +func (m *Middleware) authenticationCacheProvisionerAccount(ctx context.Context, client_uuid uuid.UUID) (*db.CachedProvisionerAccount, error) { + var provisioner_account *db.Provisioner + var instance_identity_document *db.AwsAttestation + var cached_provisioner_account db.CachedProvisionerAccount + var err error + + db_reader := m.store.Reader + uuid := client_uuid.String() + if value, cached := m.cache.Get(uuid); cached == nil { + err = json.Unmarshal(value, &cached_provisioner_account) + if err != nil { + return &cached_provisioner_account, fmt.Errorf("error unmarshal cached service account account, %s", err) + } + } else { + provisioner_account, err = db_reader.GetProvisionerUUID(ctx, client_uuid) + if err != nil { + return &cached_provisioner_account, fmt.Errorf("service authentication failed: %s", err) + } + + cached_provisioner_account.ProvisionerAccount = *provisioner_account + for _, node_attestation := range provisioner_account.NodeAttestation { + switch node_attestation { + case types.Attestation.AWS_IID: + instance_identity_document, err = aws_iid.GetInstanceIdentityDocument(ctx, db_reader, client_uuid) + if err != nil { + return &cached_provisioner_account, fmt.Errorf("aws_iid node attestation failed: %s", err) + } + cached_provisioner_account.AwsIid = *instance_identity_document + } + } + + data, err := json.Marshal(cached_provisioner_account) + if err != nil { + return &cached_provisioner_account, fmt.Errorf("error marshalling cached_service_account, %s", err) + } + err = m.cache.Set(uuid, data) + if err != nil { + return &cached_provisioner_account, fmt.Errorf("error setting middleware cache, %s", err) + } + } + return &cached_provisioner_account, nil +} diff --git a/internal/validator/validate.go b/internal/validator/validate.go index 6d5fce1..8445efb 100644 --- a/internal/validator/validate.go +++ b/internal/validator/validate.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "regexp" + "unicode" "github.com/coinbase/baseca/internal/config" "github.com/tabbed/pqtype" @@ -102,3 +103,14 @@ func ConvertNullRawMessageToMap(nrm pqtype.NullRawMessage) (map[string]string, e } return result, nil } + +// Validate if input only contain alphanumeric +func ValidateInput(s string) bool { + for _, c := range s { + if !unicode.IsLetter(c) && !unicode.IsNumber(c) { + return false + } + } + + return true +} diff --git a/pkg/client/certificate.go b/pkg/client/certificate.go index a00b71e..8385682 100644 --- a/pkg/client/certificate.go +++ b/pkg/client/certificate.go @@ -24,38 +24,10 @@ func (c *client) IssueCertificate(certificateRequest CertificateRequest) (*apiv1 } err = parseCertificateFormat(signedCertificate, SignedCertificate{ - CertificatePath: certificateRequest.Output.Certificate, - CertificateChainPath: certificateRequest.Output.CertificateChain}) - - if err != nil { - return nil, err - } - - return signedCertificate, nil -} - -func (c *client) ProvisionIssueCertificate(certificateRequest CertificateRequest, ca *apiv1.CertificateAuthorityParameter, service, environment, extendedKey string) (*apiv1.SignedCertificate, error) { - signingRequest, err := GenerateCSR(certificateRequest) - if err != nil { - return nil, err - } - - req := apiv1.OperationsSignRequest{ - CertificateSigningRequest: signingRequest.CSR.String(), - CertificateAuthority: ca, - ServiceAccount: service, - Environment: environment, - ExtendedKey: extendedKey, - } - - signedCertificate, err := c.Certificate.OperationsSignCSR(context.Background(), &req) - if err != nil { - return nil, err - } - - err = parseCertificateFormat(signedCertificate, SignedCertificate{ - CertificatePath: certificateRequest.Output.Certificate, - CertificateChainPath: certificateRequest.Output.CertificateChain}) + CertificatePath: certificateRequest.Output.Certificate, + IntermediateCertificateChainPath: certificateRequest.Output.IntermediateCertificateChain, + RootCertificateChainPath: certificateRequest.Output.RootCertificateChain, + }) if err != nil { return nil, err @@ -73,12 +45,24 @@ func parseCertificateFormat(certificate *apiv1.SignedCertificate, parameter Sign } } - // Certificate Chain Path - if len(parameter.CertificateChainPath) != 0 { + // Intermediate Certificate Chain Path + if len(parameter.IntermediateCertificateChainPath) != 0 { + certificate := []byte(certificate.IntermediateCertificateChain) + if err := os.WriteFile(parameter.IntermediateCertificateChainPath, certificate, os.ModePerm); err != nil { + return fmt.Errorf("error writing certificate to [%s]", parameter.IntermediateCertificateChainPath) + } + } + + // Root Certificate Chain Path + if len(parameter.RootCertificateChainPath) != 0 { certificate := []byte(certificate.CertificateChain) - if err := os.WriteFile(parameter.CertificateChainPath, certificate, os.ModePerm); err != nil { - return fmt.Errorf("error writing certificate chain to [%s]", parameter.CertificateChainPath) + if err := os.WriteFile(parameter.RootCertificateChainPath, certificate, os.ModePerm); err != nil { + return fmt.Errorf("error writing certificate chain to [%s]", parameter.RootCertificateChainPath) } } return nil } + +func (c *client) QueryCertificateMetadata(req *apiv1.QueryCertificateMetadataRequest) (*apiv1.CertificatesParameter, error) { + return c.Certificate.QueryCertificateMetadata(context.Background(), req) +} diff --git a/pkg/client/client.go b/pkg/client/client.go index 450a0a5..731bffa 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -14,6 +14,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/types/known/emptypb" ) // var Endpoints Environment @@ -52,11 +53,13 @@ type Provider struct { } type Output struct { - CertificateSigningRequest string - Certificate string - CertificateChain string - PrivateKey string + CertificateSigningRequest string + Certificate string + IntermediateCertificateChain string + RootCertificateChain string + PrivateKey string } + type CertificateRequest struct { CommonName string SubjectAlternateNames []string @@ -85,6 +88,7 @@ type client struct { authentication Authentication attestation string Certificate apiv1.CertificateClient + Service apiv1.ServiceClient } const ( @@ -95,6 +99,14 @@ const ( type CertificateClient interface { SignCSR(ctx context.Context, in *apiv1.CertificateSigningRequest, opts ...grpc.CallOption) (*apiv1.SignedCertificate, error) + OperationsSignCSR(ctx context.Context, in *apiv1.OperationsSignRequest, opts ...grpc.CallOption) (*apiv1.SignedCertificate, error) + QueryCertificateMetadata(ctx context.Context, in *apiv1.QueryCertificateMetadataRequest, opts ...grpc.CallOption) (*apiv1.CertificatesParameter, error) +} + +type ServiceClient interface { + ProvisionServiceAccount(ctx context.Context, in *apiv1.ProvisionServiceAccountRequest, opts ...grpc.CallOption) (*apiv1.ProvisionServiceAccountResponse, error) + GetServiceAccountByMetadata(ctx context.Context, in *apiv1.GetServiceAccountMetadataRequest, opts ...grpc.CallOption) (*apiv1.ServiceAccounts, error) + DeleteProvisionedServiceAccount(ctx context.Context, in *apiv1.AccountId, opts ...grpc.CallOption) (*emptypb.Empty, error) } func LoadDefaultConfiguration(configuration Configuration, client_id, client_token, attestation string) (*client, error) { @@ -127,9 +139,12 @@ func LoadDefaultConfiguration(configuration Configuration, client_id, client_tok func (c *client) methodInterceptor() grpc.UnaryClientInterceptor { methodOptions := map[string]grpc.UnaryClientInterceptor{ - "/baseca.v1.Certificate/SignCSR": c.clientAuthUnaryInterceptor, - "/baseca.v1.Certificate/OperationsSignCSR": c.clientAuthUnaryInterceptor, - "/baseca.v1.Service/ProvisionServiceAccount": c.clientAuthUnaryInterceptor, + "/baseca.v1.Certificate/SignCSR": c.clientAuthUnaryInterceptor, + "/baseca.v1.Certificate/OperationsSignCSR": c.clientAuthUnaryInterceptor, + "/baseca.v1.Certificate/QueryCertificateMetadata": c.clientAuthUnaryInterceptor, + "/baseca.v1.Service/ProvisionServiceAccount": c.clientAuthUnaryInterceptor, + "/baseca.v1.Service/GetServiceAccountByMetadata": c.clientAuthUnaryInterceptor, + "/baseca.v1.Service/DeleteProvisionedServiceAccount": c.clientAuthUnaryInterceptor, } return mapMethodInterceptor(methodOptions) } diff --git a/pkg/client/csr.go b/pkg/client/csr.go index b76b77a..a135789 100644 --- a/pkg/client/csr.go +++ b/pkg/client/csr.go @@ -2,6 +2,8 @@ package baseca import ( "bytes" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" @@ -18,8 +20,9 @@ type SigningRequest struct { } type SignedCertificate struct { - CertificatePath string - CertificateChainPath string + CertificatePath string + IntermediateCertificateChainPath string + RootCertificateChainPath string } func GenerateCSR(csr CertificateRequest) (*SigningRequest, error) { @@ -89,6 +92,55 @@ func GenerateCSR(csr CertificateRequest) (*SigningRequest, error) { CSR: certificatePem, PrivateKey: pkBlock, }, nil + + case x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512: + pk, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + if err != nil { + return nil, errors.New("error generating ECDSA key pair") + } + + csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, pk) + if err != nil { + return nil, err + } + + certificatePem := new(bytes.Buffer) + err = pem.Encode(certificatePem, &pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: csrBytes, + }) + + if err != nil { + return nil, errors.New("error encoding certificate request (csr)") + } + + if len(csr.Output.CertificateSigningRequest) != 0 { + if err := os.WriteFile(csr.Output.CertificateSigningRequest, certificatePem.Bytes(), os.ModePerm); err != nil { + return nil, fmt.Errorf("error writing certificate signing request (csr) to [%s]", csr.Output.CertificateSigningRequest) + } + } + + ecPrivateKeyBytes, err := x509.MarshalECPrivateKey(pk) + if err != nil { + return nil, errors.New("error marshaling ECDSA private key") + } + + pkBlock := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: ecPrivateKeyBytes, + } + + if len(csr.Output.PrivateKey) != 0 { + if err := os.WriteFile(csr.Output.PrivateKey, pem.EncodeToMemory(pkBlock), os.ModePerm); err != nil { + return nil, fmt.Errorf("error writing private key to [%s]", csr.Output.PrivateKey) + } + } + + return &SigningRequest{ + CSR: certificatePem, + PrivateKey: pkBlock, + }, nil + default: return nil, errors.New("unsupported signing algorithm") } diff --git a/pkg/client/provisioner.go b/pkg/client/provisioner.go new file mode 100644 index 0000000..ead3258 --- /dev/null +++ b/pkg/client/provisioner.go @@ -0,0 +1,47 @@ +package baseca + +import ( + "context" + + apiv1 "github.com/coinbase/baseca/gen/go/baseca/v1" +) + +func (c *client) ProvisionIssueCertificate(certificateRequest CertificateRequest, ca *apiv1.CertificateAuthorityParameter, service, environment, extendedKey string) (*apiv1.SignedCertificate, error) { + signingRequest, err := GenerateCSR(certificateRequest) + if err != nil { + return nil, err + } + + req := apiv1.OperationsSignRequest{ + CertificateSigningRequest: signingRequest.CSR.String(), + CertificateAuthority: ca, + ServiceAccount: service, + Environment: environment, + ExtendedKey: extendedKey, + } + + signedCertificate, err := c.Certificate.OperationsSignCSR(context.Background(), &req) + if err != nil { + return nil, err + } + + err = parseCertificateFormat(signedCertificate, SignedCertificate{ + CertificatePath: certificateRequest.Output.Certificate, + IntermediateCertificateChainPath: certificateRequest.Output.IntermediateCertificateChain, + RootCertificateChainPath: certificateRequest.Output.RootCertificateChain, + }) + + if err != nil { + return nil, err + } + + return signedCertificate, nil +} + +func (c *client) ProvisionServiceAccount(req *apiv1.ProvisionServiceAccountRequest) (*apiv1.ProvisionServiceAccountResponse, error) { + return c.Service.ProvisionServiceAccount(context.Background(), req) +} + +func (c *client) GetServiceAccountByMetadata(req *apiv1.GetServiceAccountMetadataRequest) (*apiv1.ServiceAccounts, error) { + return c.Service.GetServiceAccountMetadata(context.Background(), req) +} diff --git a/pkg/client/sign.go b/pkg/client/sign.go index 852ec0b..6885be9 100644 --- a/pkg/client/sign.go +++ b/pkg/client/sign.go @@ -35,8 +35,9 @@ func (c *client) GenerateSignature(csr CertificateRequest, element []byte) (*[]b } err = parseCertificateFormat(signedCertificate, SignedCertificate{ - CertificatePath: csr.Output.Certificate, - CertificateChainPath: csr.Output.CertificateChain}) + CertificatePath: csr.Output.Certificate, + IntermediateCertificateChainPath: csr.Output.IntermediateCertificateChain, + RootCertificateChainPath: csr.Output.RootCertificateChain}) if err != nil { return nil, nil, err @@ -53,7 +54,7 @@ func (c *client) GenerateSignature(csr CertificateRequest, element []byte) (*[]b return nil, nil, fmt.Errorf("error calculating signature of hash using pkcs1: %s", err) } - fullChain, err := os.ReadFile(filepath.Clean(csr.Output.CertificateChain)) + fullChain, err := os.ReadFile(filepath.Clean(csr.Output.RootCertificateChain)) if err != nil { return nil, nil, fmt.Errorf("error retrieving full chain certificate: %s", err) } diff --git a/protos/baseca/v1/api.proto b/protos/baseca/v1/api.proto index 35b9ba1..1b90a38 100644 --- a/protos/baseca/v1/api.proto +++ b/protos/baseca/v1/api.proto @@ -43,6 +43,7 @@ message SignedCertificate { string certificate = 1; string certificate_chain = 2; CertificateParameter metadata = 3; + string intermediate_certificate_chain = 4; } message CertificateSerialNumber { @@ -68,10 +69,15 @@ message RevokeCertificateResponse { message OperationsSignRequest { string certificate_signing_request = 1; - CertificateAuthorityParameter certificate_authority = 2; + optional CertificateAuthorityParameter certificate_authority = 2; string service_account = 3; string environment = 4; - string extended_key = 5;} + string extended_key = 5; +} + +message Environment { + string environment = 1; +} service Certificate { rpc SignCSR (CertificateSigningRequest) returns (SignedCertificate); @@ -79,6 +85,15 @@ service Certificate { rpc ListCertificates (ListCertificatesRequest) returns (CertificatesParameter); rpc RevokeCertificate (RevokeCertificateRequest) returns (RevokeCertificateResponse); rpc OperationsSignCSR (OperationsSignRequest) returns (SignedCertificate); + rpc QueryCertificateMetadata (QueryCertificateMetadataRequest) returns (CertificatesParameter); +} + +message QueryCertificateMetadataRequest { + string serial_number = 1; + string account = 2; + string environment = 3; + string extended_key = 4; + repeated string subject_alternative_name = 5; } message User { @@ -185,16 +200,65 @@ message ServiceAccount { string extended_key = 7; NodeAttestation node_attestation = 8; int32 certificate_validity = 9; - string team = 10; - string email = 11; - google.protobuf.Timestamp created_at = 12; - string created_by = 13; + string subordinate_ca = 10; + bool provisioned = 11; + string team = 12; + string email = 13; + google.protobuf.Timestamp created_at = 14; + string created_by = 15; } message ServiceAccounts { repeated ServiceAccount service_accounts = 1; } +message CreateProvisionerAccountRequest { + string provisioner_account = 1; + repeated string environments = 2; + string regular_expression = 3; + repeated string subject_alternative_names = 4; + repeated string extended_keys = 5; + uint32 max_certificate_validity = 6; + optional NodeAttestation node_attestation = 7; + string team = 8; + string email = 9; +} + +message CreateProvisionerAccountResponse { + string client_id = 1; + string client_token = 2; + string provisioner_account = 3; + repeated string environments = 4; + string regular_expression = 5; + repeated string subject_alternative_names = 6; + repeated string extended_keys = 8; + NodeAttestation node_attestation = 9; + uint32 max_certificate_validity = 10; + string team = 11; + string email = 12; + google.protobuf.Timestamp created_at = 13; + string created_by = 14; +} + +message ProvisionerAccounts { + repeated ProvisionerAccount provisioner_accounts = 1; +} + +message ProvisionerAccount { + string client_id = 1; + string provisioner_account = 2; + repeated string environments = 3; + string regular_expression = 4; + repeated string subject_alternative_names = 5; + repeated string extended_keys = 7; + NodeAttestation node_attestation = 8; + uint32 max_certificate_validity = 9; + string team = 10; + string email = 11; + google.protobuf.Timestamp created_at = 12; + string created_by = 13; +} + message NodeAttestation { AWSInstanceIdentityDocument aws_iid = 1; } @@ -209,29 +273,61 @@ message AWSInstanceIdentityDocument { map instance_tags = 7; } -message ServiceAccountId { +message AccountId { string uuid = 1; } -message ServiceAccountName{ +message GetServiceAccountMetadataRequest{ string service_account = 1; + string environment = 2; + string extended_key = 3; } message ProvisionServiceAccountRequest { - CreateServiceAccountRequest account = 1; + string service_account = 1; + string environment = 2; + string regular_expression = 3; + repeated string subject_alternative_names = 4; + repeated string certificate_authorities = 5; + string extended_key = 6; + int32 certificate_validity = 7; + string subordinate_ca = 8; + NodeAttestation node_attestation = 9; + string team = 10; + string email = 11; } message ProvisionServiceAccountResponse { - CreateServiceAccountResponse account = 1; + string client_id = 1; + string client_token = 2; + string service_account = 3; + string environment = 4; + string regular_expression = 5; + repeated string subject_alternative_names = 6; + repeated string certificate_authorities = 7; + string extended_key = 8; + NodeAttestation node_attestation = 9; + int32 certificate_validity = 10; + string subordinate_ca = 11; + string team = 12; + string email = 13; + google.protobuf.Timestamp created_at = 14; + string created_by = 15; } + service Service { rpc CreateServiceAccount (CreateServiceAccountRequest) returns (CreateServiceAccountResponse); + rpc CreateProvisionerAccount(CreateProvisionerAccountRequest) returns (CreateProvisionerAccountResponse); + rpc GetProvisionerAccount (AccountId) returns (ProvisionerAccount); + rpc GetServiceAccount (AccountId) returns (ServiceAccount); + rpc GetServiceAccountMetadata (GetServiceAccountMetadataRequest) returns (ServiceAccounts); + rpc DeleteServiceAccount (AccountId) returns (google.protobuf.Empty); + rpc DeleteProvisionedServiceAccount (AccountId) returns (google.protobuf.Empty); + rpc DeleteProvisionerAccount (AccountId) returns (google.protobuf.Empty); rpc ProvisionServiceAccount (ProvisionServiceAccountRequest) returns (ProvisionServiceAccountResponse); rpc ListServiceAccounts (QueryParameter) returns (ServiceAccounts); - rpc GetServiceAccountUuid (ServiceAccountId) returns (ServiceAccount); - rpc GetServiceAccountName (ServiceAccountName) returns (ServiceAccounts); - rpc DeleteServiceAccount (ServiceAccountId) returns (google.protobuf.Empty); + rpc ListProvisionerAccounts (QueryParameter) returns (ProvisionerAccounts); } message HealthCheckRequest { diff --git a/terraform/README.md b/terraform/README.md index 50e00d4..e4d7b63 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -36,7 +36,7 @@ module "baseca" { | `bucket` | S3 Bucket Name | string | false | | baseca-firehose-production | | `acm_pca_arns` | List of Private CA ARNs in Account | list(string) | false | | ["arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"]

_**NOTE:** These are upstream Intermediate CA(s) from AWS Private CA `baseca` will be issuing Subordinate CAs from._ | | `db_ingress_cidr` | IP CIDR Blocks for Ingress to RDS and Redis | list(string) | Requires `db_ingress_sg` if Not Used | | ["10.0.0.1/24", "10.0.0.2/24"] | -| `db_ingress_sg` | Security Groups for Ingress to RDS and Redis | list(string) | Requires `db_ingress_cidr` if Not Used | | ["10.0.0.1/24", "10.0.0.2/24"] | +| `db_ingress_sg` | Security Groups for Ingress to RDS and Redis | list(string) | Requires `db_ingress_cidr` if Not Used | | ["sg-0123abcd1234abcd1", "sg-5678efgh5678efgh2"] | | `db_subnet_ids` | Private Subnets to Deploy RDS Cluster

_**NOTE:** Minimum of two subnets in different availability zones._ | list(string) | false | | ["subnet-01234567", "subnet-09876543"] | | `vpc_id` | VPC ID for Security Groups

_**NOTE:** `db_subnet_ids` must be within this VPC._ | string | false | | vpc-12345678 | diff --git a/terraform/development/baseca/variables.tf b/terraform/development/baseca/variables.tf index 48eef22..cca4bdd 100644 --- a/terraform/development/baseca/variables.tf +++ b/terraform/development/baseca/variables.tf @@ -24,8 +24,3 @@ variable "bucket" { description = "Bucket Name to Store Certificate Streaming Data from Firehose" type = string } - -variable "acm_pca_arns" { - description = "List of Supported ACM Private CA ARNs" - type = list(string) -} \ No newline at end of file diff --git a/terraform/production/baseca/rds.tf b/terraform/production/baseca/rds.tf index ac1818c..ea62eab 100644 --- a/terraform/production/baseca/rds.tf +++ b/terraform/production/baseca/rds.tf @@ -16,7 +16,7 @@ resource "aws_rds_cluster" "aurora_cluster" { resource "aws_rds_cluster_instance" "cluster_instances" { count = 2 - identifier = "aurora-cluster-instance-${count.index}" + identifier = "aurora-cluster-instance-${var.service}-${count.index}" cluster_identifier = aws_rds_cluster.aurora_cluster.id instance_class = "db.t4g.medium" engine = "aurora-postgresql" diff --git a/test/config/config.test.local.sandbox.yml b/test/config/config.test.local.sandbox.yml index beeb2d4..5f1e6ca 100644 --- a/test/config/config.test.local.sandbox.yml +++ b/test/config/config.test.local.sandbox.yml @@ -17,6 +17,7 @@ redis: cluster_endpoint: xxxxxx.xxxxxx.000000.0001.use1.cache.amazonaws.com port: 6379 rate_limit: 20 + exclude_rate_limit: ["example_service"] domains: - example.com