The other day I was faced with the challenge of restoring an old backup of a GitLab instance. This is in itself is fairly straightforward process, as long as you follow the correct upgrade path. Luckily GitLab has an online tool to show you the correct path to take when doing this.

But alas, I digress. This was not the topic of this article. The challenge I was faced with during this upgrade, was when I wanted to verify user access. The instance itself only had two user accounts, both of which were protected with a MFA device. This MFA device was no longer in operation, and as such was not available for use.

This meant I had to remove the MFA device for both accounts. Having only access to the gitlab-* tools from the console and the database drove me down the path to gitlab-rails which is a CLI tool to access GitLab’s Ruby On Rails console. Using this console, you are able to perform tasks that are under the hood, or simply not available in the GUI.

To start the Rails Console, you issue the command gitlab-rails – then wait a few moments until the console boots up and is ready to use.

# gitlab-rails console
 Ruby:         ruby 3.0.6p216 (2023-03-30 revision 23a532679b) [x86_64-linux]
 GitLab:       16.6.0 (6d558d71eba) FOSS
 GitLab Shell: 14.30.0
 PostgreSQL:   13.11
------------------------------------------------------------[ booted in 12.55s ]
Loading production environment (Rails 7.0.8)

When it’s up and running, you can issue the following command to look up and display a user account’s attributes.

u = User.find_by_username("<username>")
pp u.attributes

Replace <username> with the actual user name of the account. Confirm that this is in fact the user account you want to remove the MFA device from, then use the below code to remove it.

# To turn OFF MFA in rails you need a function.

def disable_two_factor!
  transaction do
      otp_required_for_login: false,
      encrypted_otp_secret: nil,
      encrypted_otp_secret_iv: nil,
      encrypted_otp_secret_salt: nil,
      otp_grace_period_started_at: nil,
      otp_backup_codes: nil
  self.u2f_registrations.destroy_all# rubocop: disable DestroyAll

# Then run, for each user that is effected.

user = User.find_by(username: <BadUser>)

Again replacing <username> with the actual user name. This should remove the MFA device and old backup codes. A grace period for the user to add a new MFA device to their account is activated. This grace period is 48 hours from the time the MFA device was removed.

By Jostein Elvaker Haande

"A free society is a society where it is safe to be unpopular" - Adlai Stevenson

Leave a Reply

Your email address will not be published. Required fields are marked *