diff --git a/app/models/alert_management/http_integration.rb b/app/models/alert_management/http_integration.rb
index e98c770c36451df5328d86fefe150c881ec826b9..2caa9a184456d9f38f1ab475aa75d704c27babe0 100644
--- a/app/models/alert_management/http_integration.rb
+++ b/app/models/alert_management/http_integration.rb
@@ -10,7 +10,7 @@ class HttpIntegration < ApplicationRecord
 
     attr_encrypted :token,
       mode: :per_attribute_iv,
-      key: Settings.attr_encrypted_db_key_base_truncated,
+      key: Settings.attr_encrypted_db_key_base_32,
       algorithm: 'aes-256-gcm'
 
     default_value_for(:endpoint_identifier, allows_nil: false) { SecureRandom.hex(8) }
diff --git a/app/models/alerting/project_alerting_setting.rb b/app/models/alerting/project_alerting_setting.rb
index 8f8c38f11e40f3a4461b8162a7b01ef41e8fbf8f..34fa27eb29be9d74488794a806765a6321156e82 100644
--- a/app/models/alerting/project_alerting_setting.rb
+++ b/app/models/alerting/project_alerting_setting.rb
@@ -10,7 +10,7 @@ class ProjectAlertingSetting < ApplicationRecord
 
     attr_encrypted :token,
       mode: :per_attribute_iv,
-      key: Settings.attr_encrypted_db_key_base_truncated,
+      key: Settings.attr_encrypted_db_key_base_32,
       algorithm: 'aes-256-gcm'
 
     before_validation :ensure_token
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index f405f5ca5d318a2aba034305eeb35915c90d46bf..bf4acb40d9d61dc61822c0e26c973ed871e394bf 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -481,29 +481,29 @@ def self.kroki_formats_attributes
                  algorithm: 'aes-256-cbc',
                  insecure_mode: true
 
-  private_class_method def self.encryption_options_base_truncated_aes_256_gcm
+  private_class_method def self.encryption_options_base_32_aes_256_gcm
     {
       mode: :per_attribute_iv,
-      key: Settings.attr_encrypted_db_key_base_truncated,
+      key: Settings.attr_encrypted_db_key_base_32,
       algorithm: 'aes-256-gcm',
       encode: true
     }
   end
 
-  attr_encrypted :external_auth_client_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :external_auth_client_key_pass, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :lets_encrypt_private_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :eks_secret_access_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :akismet_api_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :elasticsearch_aws_secret_access_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :recaptcha_private_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :recaptcha_site_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :slack_app_secret, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :slack_app_verification_token, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :ci_jwt_signing_key, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :cloud_license_auth_token, encryption_options_base_truncated_aes_256_gcm
-  attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_truncated_aes_256_gcm
+  attr_encrypted :external_auth_client_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :external_auth_client_key_pass, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :lets_encrypt_private_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :eks_secret_access_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :akismet_api_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :elasticsearch_aws_secret_access_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :recaptcha_private_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :recaptcha_site_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :slack_app_secret, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :slack_app_verification_token, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :ci_jwt_signing_key, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :cloud_license_auth_token, encryption_options_base_32_aes_256_gcm
+  attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_32_aes_256_gcm
 
   validates :disable_feed_token,
             inclusion: { in: [true, false], message: _('must be a boolean value') }
diff --git a/app/models/atlassian/identity.rb b/app/models/atlassian/identity.rb
index 906f2be0fbf31fc38e60b2bf821dc3194727167a..02bbe007e1b1fd5dfbbfd879898659108fe201ad 100644
--- a/app/models/atlassian/identity.rb
+++ b/app/models/atlassian/identity.rb
@@ -11,14 +11,14 @@ class Identity < ApplicationRecord
 
     attr_encrypted :token,
                    mode: :per_attribute_iv,
-                   key: Settings.attr_encrypted_db_key_base_truncated,
+                   key: Settings.attr_encrypted_db_key_base_32,
                    algorithm: 'aes-256-gcm',
                    encode: false,
                    encode_iv: false
 
     attr_encrypted :refresh_token,
                    mode: :per_attribute_iv,
-                   key: Settings.attr_encrypted_db_key_base_truncated,
+                   key: Settings.attr_encrypted_db_key_base_32,
                    algorithm: 'aes-256-gcm',
                    encode: false,
                    encode_iv: false
diff --git a/app/models/bulk_imports/configuration.rb b/app/models/bulk_imports/configuration.rb
index 4c6f745c2686b5bffd01bfd3da648034d7ca78ba..6d9f598583ea050eb8c32f759ffb13e9447739ae 100644
--- a/app/models/bulk_imports/configuration.rb
+++ b/app/models/bulk_imports/configuration.rb
@@ -12,11 +12,11 @@ class BulkImports::Configuration < ApplicationRecord
     allow_nil: true
 
   attr_encrypted :url,
-    key: Settings.attr_encrypted_db_key_base_truncated,
+    key: Settings.attr_encrypted_db_key_base_32,
     mode: :per_attribute_iv,
     algorithm: 'aes-256-gcm'
   attr_encrypted :access_token,
-    key: Settings.attr_encrypted_db_key_base_truncated,
+    key: Settings.attr_encrypted_db_key_base_32,
     mode: :per_attribute_iv,
     algorithm: 'aes-256-gcm'
 end
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index b9c136abab4062735b32a5549d4c309aa19a32dd..435a970294da1b584068436dcfdd6e9aa0d1be00 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -22,7 +22,7 @@ class Prometheus < ApplicationRecord
 
       attr_encrypted :alert_manager_token,
         mode: :per_attribute_iv,
-        key: Settings.attr_encrypted_db_key_base_truncated,
+        key: Settings.attr_encrypted_db_key_base_32,
         algorithm: 'aes-256-gcm'
 
       after_destroy do
diff --git a/app/models/clusters/providers/aws.rb b/app/models/clusters/providers/aws.rb
index bfd01775620d4834c3d17c2bdbba2929ec12d85f..af2eba427219fa66fa09584d978f2c0b4350cf07 100644
--- a/app/models/clusters/providers/aws.rb
+++ b/app/models/clusters/providers/aws.rb
@@ -18,7 +18,7 @@ class Aws < ApplicationRecord
 
       attr_encrypted :secret_access_key,
         mode: :per_attribute_iv,
-        key: Settings.attr_encrypted_db_key_base_truncated,
+        key: Settings.attr_encrypted_db_key_base_32,
         algorithm: 'aes-256-gcm'
 
       validates :role_arn,
diff --git a/app/models/concerns/packages/debian/distribution.rb b/app/models/concerns/packages/debian/distribution.rb
index 08fb9ccf3ea37c105ae4b259b638bcf6e442da4a..267c7a4d201f57693380c8fc74c4a73fb873a57e 100644
--- a/app/models/concerns/packages/debian/distribution.rb
+++ b/app/models/concerns/packages/debian/distribution.rb
@@ -84,7 +84,7 @@ def self.container_foreign_key
 
         attr_encrypted :signing_keys,
                        mode: :per_attribute_iv,
-                       key: Settings.attr_encrypted_db_key_base_truncated,
+                       key: Settings.attr_encrypted_db_key_base_32,
                        algorithm: 'aes-256-gcm',
                        encode: false,
                        encode_iv: false
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb
index 9a9fbc6a801ff1362c40975e433664f5de6190af..956b5d6470f02d9013260fbec6f1c6f265d845f1 100644
--- a/app/models/error_tracking/project_error_tracking_setting.rb
+++ b/app/models/error_tracking/project_error_tracking_setting.rb
@@ -38,7 +38,7 @@ class ProjectErrorTrackingSetting < ApplicationRecord
 
     attr_encrypted :token,
       mode: :per_attribute_iv,
-      key: Settings.attr_encrypted_db_key_base_truncated,
+      key: Settings.attr_encrypted_db_key_base_32,
       algorithm: 'aes-256-gcm'
 
     after_save :clear_reactive_cache!
diff --git a/app/models/incident_management/project_incident_management_setting.rb b/app/models/incident_management/project_incident_management_setting.rb
index 4887265be8889c87a122692782f25bb6b4cfc24c..3d4cb2f19122eff3b4146749ea2693a86cfaf2bd 100644
--- a/app/models/incident_management/project_incident_management_setting.rb
+++ b/app/models/incident_management/project_incident_management_setting.rb
@@ -12,7 +12,7 @@ class ProjectIncidentManagementSetting < ApplicationRecord
 
     attr_encrypted :pagerduty_token,
       mode: :per_attribute_iv,
-      key: ::Settings.attr_encrypted_db_key_base_truncated,
+      key: ::Settings.attr_encrypted_db_key_base_32,
       algorithm: 'aes-256-gcm',
       encode: false, # No need to encode for binary column https://github.com/attr-encrypted/attr_encrypted#the-encode-encode_iv-encode_salt-and-default_encoding-options
       encode_iv: false
diff --git a/app/models/pages_domain_acme_order.rb b/app/models/pages_domain_acme_order.rb
index 411456cc237bf61bf98d5ed090e86eef722def42..8427176fa72068926d2d0f8f3a34a1f26f30eafd 100644
--- a/app/models/pages_domain_acme_order.rb
+++ b/app/models/pages_domain_acme_order.rb
@@ -14,7 +14,7 @@ class PagesDomainAcmeOrder < ApplicationRecord
 
   attr_encrypted :private_key,
                  mode: :per_attribute_iv,
-                 key: Settings.attr_encrypted_db_key_base_truncated,
+                 key: Settings.attr_encrypted_db_key_base_32,
                  algorithm: 'aes-256-gcm',
                  encode: true
 
diff --git a/app/models/serverless/domain_cluster.rb b/app/models/serverless/domain_cluster.rb
index 9f914d5c3f89d855a14803c32b949a1f7bfb26a9..0d54a97370e2efe3bdef38c37f13f19fd7cc7b35 100644
--- a/app/models/serverless/domain_cluster.rb
+++ b/app/models/serverless/domain_cluster.rb
@@ -12,7 +12,7 @@ class DomainCluster < ApplicationRecord
 
     attr_encrypted :key,
       mode: :per_attribute_iv,
-      key: Settings.attr_encrypted_db_key_base_truncated,
+      key: Settings.attr_encrypted_db_key_base_32,
       algorithm: 'aes-256-gcm'
 
     validates :pages_domain, :knative, presence: true
diff --git a/config/secrets.yml.example b/config/secrets.yml.example
index 6b408ac6031d9295c539e097a4a2d6c4872cb010..aadf13d53b2e60c22e172b8ed65e5b087700dcfa 100644
--- a/config/secrets.yml.example
+++ b/config/secrets.yml.example
@@ -1,7 +1,7 @@
 production:
   # db_key_base is used to encrypt for Variables. Ensure that you don't lose it.
   # If you change or lose this key you will be unable to access variables stored in database.
-  # Make sure the secret is at least 30 characters and all random,
+  # Make sure the secret is at least 32 characters and all random,
   # no regular words or you'll be exposed to dictionary attacks.
   # db_key_base:
 
diff --git a/config/settings.rb b/config/settings.rb
index 3369f2a448053b924be473f2e3e671b70331e03b..a88f6d89ce421ca5d298c0aa748b36b3a29ef7b0 100644
--- a/config/settings.rb
+++ b/config/settings.rb
@@ -126,16 +126,18 @@ def absolute(path)
       File.expand_path(path, Rails.root)
     end
 
-    # Ruby 2.4+ requires passing in the exact required length for OpenSSL keys
-    # (https://github.com/ruby/ruby/commit/ce635262f53b760284d56bb1027baebaaec175d1).
-    # Previous versions quietly truncated the input.
-    #
-    # Use this when using :per_attribute_iv mode for attr_encrypted.
-    # We have to truncate the string to 32 bytes for a 256-bit cipher.
+    # Don't use this in new code, use attr_encrypted_db_key_base_32 instead!
     def attr_encrypted_db_key_base_truncated
       Gitlab::Application.secrets.db_key_base[0..31]
     end
 
+    # Ruby 2.4+ requires passing in the exact required length for OpenSSL keys
+    # (https://github.com/ruby/ruby/commit/ce635262f53b760284d56bb1027baebaaec175d1).
+    # Previous versions quietly truncated the input.
+    #
+    # Makes sure the key is exactly 32 bytes long, either by
+    # truncating or right-padding it with ASCII 0s. Use this when
+    # using :per_attribute_iv mode for attr_encrypted.
     def attr_encrypted_db_key_base_32
       Gitlab::Utils.ensure_utf8_size(attr_encrypted_db_key_base, bytes: 32.bytes)
     end
diff --git a/db/migrate/20191120115530_encrypt_plaintext_attributes_on_application_settings.rb b/db/migrate/20191120115530_encrypt_plaintext_attributes_on_application_settings.rb
index e6b9a40ad4f97f526ac4d326b4a655ff7e720e4c..3ae5e3265e8330018fd370b02fbcd64812425c6c 100644
--- a/db/migrate/20191120115530_encrypt_plaintext_attributes_on_application_settings.rb
+++ b/db/migrate/20191120115530_encrypt_plaintext_attributes_on_application_settings.rb
@@ -17,21 +17,21 @@ class EncryptPlaintextAttributesOnApplicationSettings < ActiveRecord::Migration[
   class ApplicationSetting < ActiveRecord::Base
     self.table_name = 'application_settings'
 
-    def self.encryption_options_base_truncated_aes_256_gcm
+    def self.encryption_options_base_32_aes_256_gcm
       {
         mode: :per_attribute_iv,
-        key: Gitlab::Application.secrets.db_key_base[0..31],
+        key: Gitlab::Utils.ensure_utf8_size(Rails.application.secrets.db_key_base, bytes: 32.bytes),
         algorithm: 'aes-256-gcm',
         encode: true
       }
     end
 
-    attr_encrypted :akismet_api_key, encryption_options_base_truncated_aes_256_gcm
-    attr_encrypted :elasticsearch_aws_secret_access_key, encryption_options_base_truncated_aes_256_gcm
-    attr_encrypted :recaptcha_private_key, encryption_options_base_truncated_aes_256_gcm
-    attr_encrypted :recaptcha_site_key, encryption_options_base_truncated_aes_256_gcm
-    attr_encrypted :slack_app_secret, encryption_options_base_truncated_aes_256_gcm
-    attr_encrypted :slack_app_verification_token, encryption_options_base_truncated_aes_256_gcm
+    attr_encrypted :akismet_api_key, encryption_options_base_32_aes_256_gcm
+    attr_encrypted :elasticsearch_aws_secret_access_key, encryption_options_base_32_aes_256_gcm
+    attr_encrypted :recaptcha_private_key, encryption_options_base_32_aes_256_gcm
+    attr_encrypted :recaptcha_site_key, encryption_options_base_32_aes_256_gcm
+    attr_encrypted :slack_app_secret, encryption_options_base_32_aes_256_gcm
+    attr_encrypted :slack_app_verification_token, encryption_options_base_32_aes_256_gcm
 
     def akismet_api_key
       decrypt(:akismet_api_key, self[:encrypted_akismet_api_key]) || self[:akismet_api_key]
diff --git a/db/migrate/20201008013434_generate_ci_jwt_signing_key.rb b/db/migrate/20201008013434_generate_ci_jwt_signing_key.rb
index 7983a56f439be11d69032078ff269ec6294aca3f..5d7b6349fe611408d6156ebcce0d263aeb4c3cef 100644
--- a/db/migrate/20201008013434_generate_ci_jwt_signing_key.rb
+++ b/db/migrate/20201008013434_generate_ci_jwt_signing_key.rb
@@ -8,7 +8,7 @@ class ApplicationSetting < ActiveRecord::Base
 
     attr_encrypted :ci_jwt_signing_key, {
       mode: :per_attribute_iv,
-      key: Rails.application.secrets.db_key_base[0..31],
+      key: Gitlab::Utils.ensure_utf8_size(Rails.application.secrets.db_key_base, bytes: 32.bytes),
       algorithm: 'aes-256-gcm',
       encode: true
     }
diff --git a/ee/app/models/geo_node.rb b/ee/app/models/geo_node.rb
index 09a2bdc40caacd1dd8581c4a8410445ab8c45c87..bdb0e6804420f9c201272589b0114809bea313fc 100644
--- a/ee/app/models/geo_node.rb
+++ b/ee/app/models/geo_node.rb
@@ -55,7 +55,7 @@ class GeoNode < ApplicationRecord
   scope :ordered, -> { order(:id) }
 
   attr_encrypted :secret_access_key,
-                 key: Settings.attr_encrypted_db_key_base_truncated,
+                 key: Settings.attr_encrypted_db_key_base_32,
                  algorithm: 'aes-256-gcm',
                  mode: :per_attribute_iv,
                  encode: true
diff --git a/spec/migrations/generate_ci_jwt_signing_key_spec.rb b/spec/migrations/generate_ci_jwt_signing_key_spec.rb
index 4cfaa8701aa88984a195f5a3e357154a7b147921..249af3bcb5029be36ee91e5c545a007871bc7812 100644
--- a/spec/migrations/generate_ci_jwt_signing_key_spec.rb
+++ b/spec/migrations/generate_ci_jwt_signing_key_spec.rb
@@ -11,7 +11,7 @@
 
       attr_encrypted :ci_jwt_signing_key, {
         mode: :per_attribute_iv,
-        key: Rails.application.secrets.db_key_base[0..31],
+        key: Gitlab::Utils.ensure_utf8_size(Rails.application.secrets.db_key_base, bytes: 32.bytes),
         algorithm: 'aes-256-gcm',
         encode: true
       }