feat(sql): Add dynamic credential hst tables to session recording
This adds the `recording_dynamic_credential` join table and a trigger that runs as an after insert on the `recording_session` table. The join table joins the `recording_session`, `credential_vault_store_hst`, `credential_library_history_base`, and the `credential_purpose_enm` tables.
This commit is contained in:
1 parent
3769f0851c
commit
a783c91b2d
5 files changed
+178
-12
No files matched your search
@@ -0,0 +1,79 @@
|
||||
-- Copyright (c) HashiCorp, Inc.
|
||||
-- SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
begin;
|
||||
|
||||
create table recording_dynamic_credential (
|
||||
recording_id wt_public_id not null
|
||||
constraint recording_session_fk
|
||||
references recording_session (public_id)
|
||||
on delete cascade
|
||||
on update cascade,
|
||||
credential_vault_store_hst_id wt_url_safe_id not null
|
||||
constraint credential_vault_store_hst_fk
|
||||
references credential_vault_store_hst (history_id)
|
||||
on delete restrict -- History records with session recordings cannot be deleted
|
||||
on update cascade,
|
||||
credential_library_hst_id wt_url_safe_id not null
|
||||
constraint credential_library_history_base_fk
|
||||
references credential_library_history_base (history_id)
|
||||
on delete restrict -- History records with session recordings cannot be deleted
|
||||
on update cascade,
|
||||
credential_purpose text not null
|
||||
constraint credential_purpose_fkey
|
||||
references credential_purpose_enm (name)
|
||||
on delete restrict
|
||||
on update cascade,
|
||||
primary key(recording_id, credential_vault_store_hst_id, credential_library_hst_id, credential_purpose)
|
||||
);
|
||||
comment on table recording_dynamic_credential is
|
||||
'recording_dynamic_credential table is a join table that associates a session recording with '
|
||||
'a credential library, the credential library''s credential store, '
|
||||
'and the purpose of the credential produced by the library '
|
||||
'along with the values of those entities at the time of the recording. '
|
||||
'These values are also stored in the BSR file.';
|
||||
|
||||
create function insert_recording_dynamic_credentials() returns trigger
|
||||
as $$
|
||||
begin
|
||||
with
|
||||
session_recording(session_id, recording_id) as (
|
||||
select session_id, public_id
|
||||
from recording_session
|
||||
where session_id = new.session_id
|
||||
),
|
||||
session_dynamic_creds(library_id, purpose, recording_id) as (
|
||||
select library_id, credential_purpose, recording_id
|
||||
from session_credential_dynamic
|
||||
join session_recording using (session_id)
|
||||
),
|
||||
library_history(public_id, store_id, library_hst_id, valid_range) as (
|
||||
select public_id, store_id, history_id, valid_range
|
||||
from credential_vault_library_hst
|
||||
union
|
||||
select public_id, store_id, history_id, valid_range
|
||||
from credential_vault_ssh_cert_library_hst
|
||||
),
|
||||
final(recording_id, library_id, store_id, library_hst_id, store_hst_id, cred_purpose) as (
|
||||
select sdc.recording_id, lib.public_id, lib.store_id, lib.library_hst_id, store_hst.history_id, sdc.purpose
|
||||
from library_history as lib
|
||||
join credential_vault_store_hst as store_hst on lib.store_id = store_hst.public_id
|
||||
and store_hst.valid_range @> current_timestamp
|
||||
join session_dynamic_creds as sdc on lib.public_id = sdc.library_id
|
||||
where lib.public_id in (select library_id from session_dynamic_creds)
|
||||
and lib.valid_range @> current_timestamp
|
||||
)
|
||||
insert into recording_dynamic_credential
|
||||
(recording_id, credential_vault_store_hst_id, credential_library_hst_id, credential_purpose)
|
||||
select recording_id, store_hst_id, library_hst_id, cred_purpose
|
||||
from final;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function insert_recording_dynamic_credentials is
|
||||
'insert_recording_dynamic_credentials is an after insert trigger for the recording_session table.';
|
||||
|
||||
create trigger insert_recording_dynamic_credentials after insert on recording_session
|
||||
for each row execute procedure insert_recording_dynamic_credentials();
|
||||
|
||||
commit;
|
||||
@@ -440,6 +440,13 @@ begin;
|
||||
('cvs__rcolors', 'cvl_______r1', 'red vault library', 'None', '/secrets', 'GET'),
|
||||
('cvs__gcolors', 'cvl_______g1', 'green vault library', 'None', '/secrets', 'GET');
|
||||
|
||||
insert into credential_vault_ssh_cert_library
|
||||
(store_id, public_id, name, vault_path, username, key_type, key_bits)
|
||||
values
|
||||
('cvs__bcolors', 'cvl__ssh__b1', 'blue vault ssh library', '/ssh/sign/blue', 'admin', 'ed25519', 0),
|
||||
('cvs__rcolors', 'cvl__ssh__r1', 'red vault ssh library', '/ssh/issue/red', 'webdev', 'ecdsa', 521),
|
||||
('cvs__gcolors', 'cvl__ssh__g1', 'green vault ssh library', '/ssh/issue/green', 'dba', 'rsa', 4096);
|
||||
|
||||
insert into credential_static_store
|
||||
(project_id, public_id, name, description)
|
||||
values
|
||||
@@ -480,8 +487,10 @@ begin;
|
||||
insert into target_credential_library
|
||||
(project_id, target_id, credential_library_id, credential_purpose)
|
||||
values
|
||||
('p____bcolors', 't_________cb', 'cvl_______b1', 'brokered'),
|
||||
('p____bcolors', 'tssh______cb', 'cvl_______b1', 'brokered');
|
||||
('p____bcolors', 't_________cb', 'cvl_______b1', 'brokered'),
|
||||
('p____bcolors', 'tssh______cb', 'cvl__ssh__b1', 'brokered'),
|
||||
('p____gcolors', 'tssh______cg', 'cvl_______g1', 'brokered'),
|
||||
('p____gcolors', 'tssh______cg', 'cvl__ssh__g1', 'injected_application');
|
||||
|
||||
insert into session
|
||||
(project_id, target_id, public_id, user_id, auth_token_id, certificate, endpoint)
|
||||
@@ -511,6 +520,12 @@ begin;
|
||||
('s2______cora', 'csj__gcolors', 'brokered'), -- tssh______cg
|
||||
('s2______cora', 'cspk_gcolors', 'injected_application'); -- tssh______cg
|
||||
|
||||
insert into session_credential_dynamic
|
||||
(session_id, library_id, credential_purpose)
|
||||
values
|
||||
('s1______cora', 'cvl_______g1', 'brokered'), -- tssh______cg
|
||||
('s1______cora', 'cvl__ssh__g1', 'injected_application'); -- tssh______cg
|
||||
|
||||
insert into session_host_set_host
|
||||
(session_id, host_set_id, host_id)
|
||||
values
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
-- Copyright (c) HashiCorp, Inc.
|
||||
-- SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
begin;
|
||||
select plan(27);
|
||||
|
||||
select has_table('recording_dynamic_credential');
|
||||
|
||||
-- tests a fk column referencing a history table
|
||||
-- add 5 to the plan for each time this function is called
|
||||
create function hst_fk_column(column_name name, pk_table name) returns text
|
||||
as $$
|
||||
select * from collect_tap(
|
||||
has_column('recording_dynamic_credential', column_name),
|
||||
col_not_null('recording_dynamic_credential', column_name),
|
||||
col_type_is('recording_dynamic_credential', column_name, 'wt_url_safe_id'), -- should be the same type as the operational table
|
||||
col_hasnt_default('recording_dynamic_credential', column_name),
|
||||
fk_ok('recording_dynamic_credential', column_name, pk_table, 'history_id')
|
||||
);
|
||||
$$ language sql;
|
||||
|
||||
select hst_fk_column('credential_vault_store_hst_id', 'credential_vault_store_hst');
|
||||
select hst_fk_column('credential_library_hst_id', 'credential_library_history_base');
|
||||
|
||||
select has_column('recording_dynamic_credential', 'recording_id');
|
||||
select col_not_null('recording_dynamic_credential', 'recording_id');
|
||||
select col_type_is('recording_dynamic_credential', 'recording_id', 'wt_public_id'); -- should be the same type as the operational table
|
||||
select col_hasnt_default('recording_dynamic_credential', 'recording_id');
|
||||
select fk_ok('recording_dynamic_credential', 'recording_id', 'recording_session', 'public_id');
|
||||
|
||||
select has_column('recording_dynamic_credential', 'credential_purpose');
|
||||
select col_not_null('recording_dynamic_credential', 'credential_purpose');
|
||||
select col_type_is('recording_dynamic_credential', 'credential_purpose', 'text'); -- should be the same type as the operational table
|
||||
select col_hasnt_default('recording_dynamic_credential', 'credential_purpose');
|
||||
select fk_ok('recording_dynamic_credential', 'credential_purpose', 'credential_purpose_enm', 'name');
|
||||
|
||||
select col_is_pk('recording_dynamic_credential',
|
||||
array['recording_id', 'credential_vault_store_hst_id', 'credential_library_hst_id', 'credential_purpose']);
|
||||
|
||||
prepare get_target_creds as
|
||||
select credential_library_id, credential_purpose
|
||||
from target_credential_library
|
||||
where target_id = 'tssh______cg';
|
||||
|
||||
prepare get_session_creds as
|
||||
select library_id, credential_purpose
|
||||
from session_credential_dynamic
|
||||
join session on session_id = public_id
|
||||
where target_id = 'tssh______cg'
|
||||
and session_id = 's1______cora';
|
||||
|
||||
select results_eq('get_target_creds', 'get_session_creds');
|
||||
|
||||
select is(count(*), 2::bigint)
|
||||
from target_credential_library
|
||||
where target_id = 'tssh______cg';
|
||||
|
||||
select is(count(*), 2::bigint)
|
||||
from session_credential_dynamic
|
||||
where session_id = 's1______cora';
|
||||
|
||||
select is(count(*), 1::bigint)
|
||||
from recording_session
|
||||
where session_id = 's1______cora'
|
||||
and public_id = 'sr1_____cora';
|
||||
|
||||
select is(count(*), 2::bigint)
|
||||
from recording_dynamic_credential
|
||||
where recording_id = 'sr1_____cora';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -6,10 +6,10 @@ begin;
|
||||
select plan(6);
|
||||
|
||||
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets', 'credentials');
|
||||
-- ensure no existing dimensions or bridge table rows
|
||||
|
||||
select is(count(*), 0::bigint) from wh_credential_dimension where organization_id = 'o_____widget';
|
||||
select is(count(*), 0::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 0::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
select is(count(*), 2::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 1::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
|
||||
--- insert single credential
|
||||
insert into session
|
||||
@@ -26,8 +26,8 @@ begin;
|
||||
('s1____walter', 'vl______wvl1', null, 'brokered');
|
||||
|
||||
select is(count(*), 1::bigint) from wh_credential_dimension where organization_id = 'o_____widget';
|
||||
select is(count(*), 1::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 1::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
select is(count(*), 3::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 2::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
@@ -6,10 +6,10 @@ begin;
|
||||
select plan(6);
|
||||
|
||||
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets', 'credentials');
|
||||
-- ensure no existing dimensions
|
||||
|
||||
select is(count(*), 0::bigint) from wh_credential_dimension where organization_id = 'o_____widget';
|
||||
select is(count(*), 0::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 0::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
select is(count(*), 2::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 1::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
|
||||
--- multiple single credentials
|
||||
insert into session
|
||||
@@ -29,8 +29,8 @@ begin;
|
||||
('s1____walter', 'vl______wvl3', null, 'injected_application');
|
||||
|
||||
select is(count(*), 4::bigint) from wh_credential_dimension where organization_id = 'o_____widget';
|
||||
select is(count(*), 4::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 1::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
select is(count(*), 6::bigint) from wh_credential_group_membership where credential_group_key != 'no credentials' and credential_group_key != 'Unknown';
|
||||
select is(count(*), 2::bigint) from wh_credential_group where key != 'no credentials' and key != 'Unknown';
|
||||
|
||||
select * from finish();
|
||||
rollback;
|
||||
Reference in new issue
Block a user