refactor (kms): adopt the go-kms-wrapping/extras/kms package (#2027)

* feature (db): add Db.UnderlyingDB()

This is needed to allow for integration with bits that need a *dbw.DB

* feature (kms): add new go-kms-wrapping/extras/kms dependency

* refactor (kms): schema changes required to adopt extras/kms pkg

* refactor (kms/iam): rename to DeprecateCreateKeysTx(...)

* refactor (kms): remove deprecated test

* refactor (kms): refactor Kms type

This refactor includes renaming the existing type to DeprecatedKms
and then refactoring the Kms type to become a wrapper of
go-kms-wrapping/extras/kms

* refactor (kms): delete all the unneeded bits

All this stuff is not needed now that we're using
go-kms-wrapping/extras/kms

* refactor (db): fixup tests after kms refactor

* refactor (kms/tests): use testing.TB for test helpers

Our test helper packages were not possible to use
with benchmarks. This refactor switches to testing.TB
to allow both tests and benchmarks to use the helpers.

* tests (session benchmarks): refactor to use new Kms type

* refactor (schema): rm test which relies on deprecated Kms code

* refactor (kms): post rebase on main changes required

* chore (kms refactor): re-add unit test from main

* refactor (kms): uses migrations that don't include KMS schema changes
This commit is contained in:
Jim authored and GitHub committed 2022-05-13 13:53:22 -04:00
1 parent 8cef1017e9
commit 785241237e
97 files changed
+2580 -15154

No files matched your search

@@ -0,0 +1,103 @@
begin;
-- make the required schema changes to adopt
-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2
-- this migration is from:
-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/01_domain_types.up.sql
create domain kms_private_id as text
not null
check(
length(trim(value)) > 0
);
comment on domain kms_private_id is
'standard column for private id';
create domain kms_scope_id as text
check(
length(trim(value)) > 0
);
comment on domain kms_scope_id is
'standard column for scope id';
create domain kms_timestamp as
timestamp with time zone
default current_timestamp;
comment on domain kms_timestamp is
'Standard timestamp for all create_time and update_time columns';
create domain kms_version as bigint
default 1
not null
check(
value > 0
);
comment on domain kms_version is
'standard column for row version';
-- kms_immutable_columns() will make the column names immutable which are passed as
-- parameters when the trigger is created. It raises error code 23601 which is a
-- class 23 integrity constraint violation: immutable column
create function kms_immutable_columns()
returns trigger
as $$
declare
col_name text;
new_value text;
old_value text;
begin
foreach col_name in array tg_argv loop
execute format('SELECT $1.%I', col_name) into new_value using new;
execute format('SELECT $1.%I', col_name) into old_value using old;
if new_value is distinct from old_value then
raise exception 'immutable column: %.%', tg_table_name, col_name using
errcode = '23601',
schema = tg_table_schema,
table = tg_table_name,
column = col_name;
end if;
end loop;
return new;
end;
$$ language plpgsql;
comment on function
kms_immutable_columns()
is
'function used in before update triggers to make columns immutable';
create function kms_default_create_time()
returns trigger
as $$
begin
if new.create_time is distinct from now() then
new.create_time = now();
end if;
return new;
end;
$$ language plpgsql;
comment on function
kms_default_create_time()
is
'function used to properly set create_time columns';
create function
kms_update_time_column()
returns trigger
as $$
begin
if row(new.*) is distinct from row(old.*) then
new.update_time = now();
return new;
else
return old;
end if;
end;
$$ language plpgsql;
comment on function
kms_update_time_column()
is
'function used in before update triggers to properly set update_time columns';
commit;
@@ -0,0 +1,40 @@
begin;
-- make the required schema changes to adopt
-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2
-- this migration is from:
-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/02_version.up.sql
create table kms_schema_version(
version text not null,
create_time kms_timestamp,
update_time kms_timestamp
);
comment on table kms_schema_version is
'kms_schema_version contains the kms schema version';
-- this index ensures that there will only ever be one row in the
-- table. see:
-- https://www.postgresql.org/docs/current/indexes-expressional.html
create unique index kms_schema_version_one_row
ON kms_schema_version((version is not null));
-- define the immutable fields for kms_root_key (all of them)
create trigger kms_immutable_columns
before
update on kms_schema_version
for each row execute procedure kms_immutable_columns('create_time');
create trigger kms_default_create_time_column
before
insert on kms_schema_version
for each row execute procedure kms_default_create_time();
create trigger kms_update_time_column
before
update on kms_schema_version
for each row execute procedure kms_update_time_column();
insert into kms_schema_version(version) values('v0.0.1');
commit;
@@ -0,0 +1,37 @@
begin;
-- make the required schema changes to adopt
-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2
-- this migration is from:
-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/03_keys.up.sql
-- we need to replace the existing function and there are existing tables that
-- depend on it.. so let's just create/replace it
-- kms_version_column() will increment the version column whenever row data
-- is inserted and should only be used in an before insert trigger. This
-- function will overwrite any explicit values to the version column.
create or replace function kms_version_column()
returns trigger
as $$
declare
_key_id text;
_max bigint;
begin
execute format('SELECT $1.%I', tg_argv[0]) into _key_id using new;
execute format('select max(version) + 1 from %I where %I = $1', tg_relid::regclass, tg_argv[0]) using _key_id into _max;
if _max is null then
_max = 1;
end if;
new.version = _max;
return new;
end;
$$ language plpgsql;
comment on function
kms_version_column()
is
'function used in before insert triggers to properly set version columns for kms_* tables with a version column';
commit;
@@ -0,0 +1,281 @@
begin;
-- make the required schema changes to adopt
-- github.com/hashicorp/go-kms-wrapping/extras/kms/v2
-- this migration is from:
-- https://github.com/hashicorp/go-kms-wrapping/blob/main/extras/kms/migrations/postgres/04_keys.up.sql
alter table kms_root_key rename to kms_deprecated_root_key;
alter table kms_root_key_version rename to kms_deprecated_root_key_version;
create table kms_root_key (
private_id kms_private_id primary key,
scope_id kms_scope_id not null unique -- there can only be one root key for a scope.
references iam_scope(public_id)
on delete cascade
on update cascade,
create_time kms_timestamp
);
comment on table kms_root_key is
'kms_root_key defines a root key for a scope';
-- define the immutable fields for kms_root_key (all of them)
create trigger kms_immutable_columns
before
update on kms_root_key
for each row execute procedure kms_immutable_columns('private_id', 'scope_id', 'create_time');
-- not adding the kms_default_create_time_column trigger until after we've
-- converted the data (we don't want the timestamp to change)
create table kms_root_key_version (
private_id kms_private_id primary key,
root_key_id kms_private_id not null
constraint kms_root_key_fkey
references kms_root_key(private_id)
on delete cascade
on update cascade,
version kms_version,
key bytea not null
constraint not_empty_key
check (
length(key) > 0
),
create_time kms_timestamp,
constraint kms_root_key_version_root_key_id_version_uq
unique(root_key_id, version)
);
comment on table kms_root_key_version is
'kms_root_key_version contains versions of a kms_root_key';
-- define the immutable fields for kms_root_key_version (all of them)
create trigger kms_immutable_columns
before
update on kms_root_key_version
for each row execute procedure kms_immutable_columns('private_id', 'root_key_id', 'version', 'key', 'create_time');
-- not adding the kms_default_create_time_column or kms_version_column triggers
-- until after we've converted the data (we don't want the timestamp or versions
-- to change)
create table kms_data_key (
private_id kms_private_id primary key,
root_key_id kms_private_id not null
constraint kms_root_key_fkey
references kms_root_key(private_id)
on delete cascade
on update cascade,
purpose text not null
constraint not_start_end_whitespace_purpose
check (length(trim(purpose)) = length(purpose)),
create_time kms_timestamp,
constraint kms_data_key_root_key_id_purpose_uq
unique (root_key_id, purpose) -- there can only be one dek for a specific purpose per root key
);
comment on table kms_data_key is
'kms_data_key contains deks (data keys) for specific purposes';
-- define the immutable fields for kms_data_key (all of them)
create trigger kms_immutable_columns
before
update on kms_data_key
for each row execute procedure kms_immutable_columns('private_id', 'root_key_id', 'purpose', 'create_time');
-- not adding the kms_default_create_time_column trigger until after we've
-- converted the data (we don't want the timestamp to change)
create table kms_data_key_version (
private_id kms_private_id primary key,
data_key_id kms_private_id not null
constraint kms_data_key_fkey
references kms_data_key(private_id)
on delete cascade
on update cascade,
root_key_version_id kms_private_id not null
constraint kms_root_key_version_fkey
references kms_root_key_version(private_id)
on delete cascade
on update cascade,
version kms_version,
key bytea not null
constraint not_empty_key
check (
length(key) > 0
),
create_time kms_timestamp,
constraint kms_data_key_version_data_key_id_version_uq
unique(data_key_id, version)
);
comment on table kms_data_key is
'kms_data_key_version contains versions of a kms_data_key (dek aka data keys)';
-- define the immutable fields for kms_data_key_version (all of them)
create trigger kms_immutable_columns
before
update on kms_data_key_version
for each row execute procedure immutable_columns('private_id', 'data_key_id', 'root_key_version_id', 'version', 'key', 'create_time');
-- not adding the kms_default_create_time_column or kms_version_column triggers
-- until after we've converted the data (we don't want the timestamp or versions
-- to change)
-- ############################################################################
-- Next: we will convert all the existing KEKs/DEKs into the new schema model
-- before adding triggers for create_time, and version
-- this is important, especially for the version column!
-- convert KEK tables
insert into kms_root_key (private_id, scope_id, create_time)
select private_id, scope_id, create_time
from kms_deprecated_root_key;
insert into kms_root_key_version (private_id, root_key_id, version, key, create_time)
select private_id, root_key_id, version, key, create_time
from kms_deprecated_root_key_version;
-- convert database DEK tables
insert into kms_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'database', create_time
from kms_database_key;
insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select private_id, database_key_id, root_key_version_id, version, key, create_time
from kms_database_key_version;
-- convert oplog DEK tables
insert into kms_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'oplog', create_time
from kms_oplog_key;
insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select private_id, oplog_key_id, root_key_version_id, version, key, create_time
from kms_oplog_key_version;
-- convert the audit DEK tables
insert into kms_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'audit', create_time
from kms_audit_key;
insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select private_id, audit_key_id, root_key_version_id, version, key, create_time
from kms_audit_key_version;
-- convert the oidc DEK tables
insert into kms_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'oidc', create_time
from kms_oidc_key;
insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select private_id, oidc_key_id, root_key_version_id, version, key, create_time
from kms_oidc_key_version;
-- convert the token DEK tables
insert into kms_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'tokens', create_time
from kms_token_key;
insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select private_id, token_key_id, root_key_version_id, version, key, create_time
from kms_token_key_version;
-- convert the session DEK tables
insert into kms_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'sessions', create_time
from kms_session_key;
insert into kms_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select private_id, session_key_id, root_key_version_id, version, key, create_time
from kms_session_key_version;
-- ############################################################################
-- post conversion, we add the required triggers
create trigger kms_default_create_time_column
before
insert on kms_root_key
for each row execute procedure kms_default_create_time();
create trigger kms_default_create_time_column
before
insert on kms_root_key_version
for each row execute procedure kms_default_create_time();
create trigger kms_version_column
before insert on kms_root_key_version
for each row execute procedure kms_version_column('root_key_id');
create trigger default_create_time_column
before
insert on kms_data_key
for each row execute procedure kms_default_create_time();
create trigger default_create_time
before
insert on kms_data_key_version
for each row execute procedure kms_default_create_time();
create trigger kms_version_column
before insert on kms_data_key_version
for each row execute procedure kms_version_column('data_key_id');
-- Next: we will convert all the existing DEKs FKs to the new model
alter table credential_vault_token drop constraint kms_database_key_version_fkey;
alter table credential_vault_token
add constraint kms_data_key_version_fkey
foreign key(key_id)
references kms_data_key_version (private_id)
on delete restrict
on update cascade;
alter table credential_vault_client_certificate drop constraint kms_database_key_version_fkey;
alter table credential_vault_client_certificate
add constraint kms_data_key_version_fkey
foreign key(key_id)
references kms_data_key_version (private_id)
on delete restrict
on update cascade;
alter table auth_oidc_method drop constraint kms_database_key_version_fkey;
alter table auth_oidc_method
add constraint kms_data_key_version_fkey
foreign key(key_id)
references kms_data_key_version (private_id)
on delete restrict
on update cascade;
alter table host_plugin_catalog_secret drop constraint kms_database_key_version_fkey;
alter table host_plugin_catalog_secret
add constraint kms_data_key_version_fkey
foreign key(key_id)
references kms_data_key_version (private_id)
on delete restrict
on update cascade;
alter table session_credential drop constraint kms_database_key_version_fkey;
alter table session_credential
add constraint kms_data_key_version_fkey
foreign key(key_id)
references kms_data_key_version (private_id)
on delete restrict
on update cascade;
-- rename tables so we know that they won't be used by mistake
alter table kms_database_key_version rename to kms_deprecated_database_key_version;
alter table kms_database_key rename to kms_deprecated_database_key;
alter table kms_oplog_key_version rename to kms_deprecated_oplog_key_version;
alter table kms_oplog_key rename to kms_deprecated_oplog_key;
alter table kms_audit_key_version rename to kms_deprecated_audit_key_version;
alter table kms_audit_key rename to kms_audit_database_key;
alter table kms_oidc_key_version rename to kms_deprecated_oidc_key_version;
alter table kms_oidc_key rename to kms_deprecated_oidc_key;
alter table kms_session_key_version rename to kms_deprecated_session_key_version;
alter table kms_session_key rename to kms_deprecated_session_key;
alter table kms_token_key_version rename to kms_deprecated_token_key_version;
alter table kms_token_key rename to kms_deprecated_token_key;
commit;