-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add export command to gather data needed to migrate to EE (#641)
* Add export command to gather data needed to migrate to EE * Add test for `conjurctl export` * Update changelog
- Loading branch information
Showing
6 changed files
with
150 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Feature: Export Conjur Open Source data | ||
|
||
The database and data key from Conjur can be exported to import | ||
into a Conjur EE appliance | ||
|
||
Scenario: Export using `conjurctl` | ||
When I run conjurctl export | ||
Then the export file exists |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
When(/^I run conjurctl export$/) do | ||
system("conjurctl export -o cuke_export/") || fail | ||
end | ||
|
||
Then(/^the export file exists$/) do | ||
Dir['cuke_export/*.tar.xz.gpg'].any? || fail | ||
File.exists?('cuke_export/key') || fail | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'fileutils' | ||
require 'time' | ||
require 'pathname' | ||
|
||
desc 'Export the Conjur data necessary to migrate to Enterprise Edition' | ||
task :export, ['out_dir'] do |_t, args| | ||
out_dir = Pathname.new args[:out_dir] | ||
|
||
puts "Exporting to '#{out_dir}'..." | ||
ExportTask.create_export_directory(out_dir) | ||
export_key_file = ExportTask.ensure_export_key(out_dir) | ||
|
||
dbdump = data_key_file = archive_file = nil | ||
ExportTask.with_umask 077 do | ||
dbdump = ExportTask.export_database(out_dir) | ||
data_key_file = ExportTask.export_data_key(out_dir) | ||
archive_file = ExportTask.create_export_archive(out_dir, dbdump, data_key_file) | ||
end | ||
|
||
ExportTask.encrypt_export_archive(export_key_file, archive_file) | ||
|
||
puts | ||
puts "Export placed in #{archive_file}.gpg" | ||
puts "It's encrypted with key in #{export_key_file}." | ||
puts "If you're going to store the export, make" | ||
puts 'sure to store the key file separately.' | ||
|
||
ensure | ||
ExportTask.cleanup_export_files(archive_file, out_dir) | ||
end | ||
|
||
module ExportTask | ||
class << self | ||
def create_export_directory(out_dir) | ||
# Make sure output directory exists and we can write to it | ||
FileUtils.mkpath(out_dir) | ||
FileUtils.chmod(0770, out_dir) | ||
end | ||
|
||
def ensure_export_key(out_dir) | ||
export_key_file = out_dir.join('key') | ||
if File.exist?(export_key_file) | ||
puts "Using key from #{export_key_file}" | ||
else | ||
generate_key(export_key_file) | ||
end | ||
export_key_file | ||
end | ||
|
||
def export_database(out_dir) | ||
# Export Conjur database | ||
FileUtils.mkpath out_dir.join('backup') | ||
dbdump = out_dir.join('backup/conjur.db') | ||
call(%(pg_dump -Fc -f \"#{dbdump}\" #{ENV['DATABASE_URL']})) || | ||
raise('unable to get database backup') | ||
dbdump | ||
end | ||
|
||
def export_data_key(out_dir) | ||
# export CONJUR_DATA_KEY | ||
FileUtils.mkpath out_dir.join('etc') | ||
data_key_file = out_dir.join('etc/possum.key') | ||
File.write(data_key_file, "CONJUR_DATA_KEY=#{ENV['CONJUR_DATA_KEY']}\n") | ||
data_key_file | ||
end | ||
|
||
def create_export_archive(out_dir, dbdump, data_key_file) | ||
# Timestamp to name export file | ||
timestamp = Time.now.strftime('%Y-%m-%dT%H-%M-%SZ') | ||
|
||
archive_file = out_dir.join("#{timestamp}.tar.xz") | ||
call(%(tar Jcf "#{archive_file}" -C "#{out_dir}" ) + | ||
%(--transform="s|^|/opt/conjur/|" ) + | ||
%("#{dbdump.relative_path_from(out_dir)}" "#{data_key_file.relative_path_from(out_dir)}")) || | ||
raise('unable to make archive for backup') | ||
archive_file | ||
end | ||
|
||
def encrypt_export_archive(export_key_file, archive_file) | ||
call %(gpg -c --cipher-algo AES256 --batch --passphrase-file ) + | ||
%("#{export_key_file}" --no-use-agent "#{archive_file}") | ||
end | ||
|
||
def cleanup_export_files(archive_file, out_dir) | ||
call(%(rm -rf "#{archive_file}" "#{out_dir.join('backup')}" "#{out_dir.join('etc')}")) || | ||
warn('unable to remove temporary files') | ||
end | ||
|
||
def call(*args) | ||
system(*args).tap do |result| | ||
warn "command #{Array(args).join(' ')} failed" unless result | ||
end | ||
end | ||
|
||
def generate_key(file) | ||
with_umask 077 do | ||
puts "Generating key file #{file}" | ||
File.write(file, SecureRandom.base64(64)) | ||
end | ||
end | ||
|
||
def with_umask(umask) | ||
saved_umask = File.umask umask | ||
begin | ||
yield | ||
ensure | ||
File.umask saved_umask | ||
end | ||
end | ||
end | ||
end |