Skip to content

Add Integration.encrypted_properties

Alex Kalderimis requested to merge 36385-encrypt-integration-properties into master

What does this MR do and why?

This MR encrypts Integration.properties. It acts adds new columns, and a background migration ensures that all properties are encrypted at rest once complete.

The old plain text column is not removed, and the unencrypted data will remain until removed in a subsequent migration (!80510 (merged))

Database review section:

Migration output:

Console output:

== 20220204194300 AddIntegrationsEncryptedProperties: migrating ================
-- add_column(:integrations, :encrypted_properties, :text)
   -> 0.0041s
== 20220204194300 AddIntegrationsEncryptedProperties: migrated (0.0041s) =======

== 20220204194347 EncryptIntegrationProperties: migrating =====================
-- Scheduled 1 EncryptIntegrationProperties jobs with a maximum of 1000 records per batch and an interval of 120 seconds.

The migration is expected to take at least 120 seconds. Expect all jobs to have completed after 2022-02-08 20:11:46 UTC."
== 20220204194347 EncryptIntegrationProperties: migrated (0.0933s) ============

Output of calling the background data migration

[3] pry(main)> Gitlab::BackgroundMigration::EncryptIntegrationProperties.new.perform(0, 5)
   (0.6ms)  SELECT "integrations"."id", "integrations"."properties" FROM "integrations" WHERE "integrations"."properties" IS NOT NULL AND "integrations"."id" BETWEEN 0 AND 5 /*application:console,db_config_name:main,line:/data/cache/bundle-2.7.4/ruby/2.7.0/gems/marginalia-1.10.0/lib/marginalia/comment.rb:25:in `block in construct_comment'*/
   (2.7ms)  WITH cte(cte_id, encrypted) AS MATERIALIZED ( SELECT * FROM (VALUES (1, 'Cj4ZpAGYJJhOTGWdsSWDQD3o5LW8peOHRA=='),(2, 'Cj4ZpAGYJJhOTGWdsSWDQD3o5LW8peOHRA=='),(3, 'Cj4ZpAGYJJhOTGWdsSWDQD3o5LW8peOHRA=='),(4, 'Cj4ZpAGYJJhOTGWdsSWDQD3o5LW8peOHRA=='),(5, 'Cj4ZpAGYJJhOTGWdsSWDQD3o5LW8peOHRA==')) AS t (id, props) ) UPDATE integrations SET properties = encrypted FROM cte WHERE cte_id = id /*application:console,db_config_name:main,line:/data/cache/bundle-2.7.4/ruby/2.7.0/gems/marginalia-1.10.0/lib/marginalia/comment.rb:25:in `block in construct_comment'*/
  Gitlab::Database::BackgroundMigrationJob Update All (1.0ms)  UPDATE "background_migration_jobs" SET status = 1, updated_at = NOW() WHERE "background_migration_jobs"."status" = 0 AND "background_migration_jobs"."class_name" = 'EncryptIntegrationProperties' AND (arguments = '[0,5]') /*application:console,db_config_name:main,line:/data/cache/bundle-2.7.4/ruby/2.7.0/gems/marginalia-1.10.0/lib/marginalia/comment.rb:25:in `block in construct_comment'*/
=> 0

How to set up and validate locally

To validate locally:

  1. Run the DB migrations:
max_id = Integration.maximum(:id)
Gitlab::BackgroundMigration::EncryptIntegrationProperties.new.perform(0, max_id)
  1. Verify that the encrypted column can be read successfully.
Integration.pluck(:id, :properties, :encrypted_properties)
  1. In the psql console, view the integrations table:
select properties, encrypted_properties from integrations

Observe that all of these properties are encrypted at rest.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #36385

Edited by Alex Kalderimis

Merge request reports

Loading