Skip to content
Snippets Groups Projects
Commit d1139c96 authored by Balasankar 'Balu' C's avatar Balasankar 'Balu' C
Browse files

Merge branch '7452-add-userspace-way-to-reapply-sepolicy' into 'master'

parents 3c1c3389 76e6ef26
No related branches found
No related tags found
3 merge requests!128heptapod#1534: making 1.5 the oldstable,!125heptapod#1494: make 1.5 the new stable,!124Upstream 16.11 quasi branching point
......@@ -174,7 +174,14 @@
#### Diagnose and resolve SELinux issues
Omnibus GitLab detects default path changes in `/etc/gitlab/gitlab.rb` and should apply
the correct file contexts. For installations using custom data path configuration,
the correct file contexts.
NOTE:
From GitLab 16.10 forward, administrators can try `gitlab-ctl apply-sepolicy`
to automatically fix SELinux issues. Consult
`gitlab-ctl apply-sepolicy --help` for runtime options.
For installations using custom data path configuration,
the administrator may have to manually resolve SELinux issues.
Data paths may be altered via `gitlab.rb`, however, a common scenario forces the
......
......@@ -10,7 +10,7 @@
true
end
def commands(node)
def commands(node, dry_run: false)
ssh_dir = File.join(node['gitlab']['user']['home'], ".ssh")
authorized_keys = node['gitlab']['gitlab_shell']['auth_file']
gitlab_shell_var_dir = node['gitlab']['gitlab_shell']['dir']
......@@ -19,8 +19,10 @@
gitlab_rails_etc_dir = File.join(gitlab_rails_dir, "etc")
gitlab_shell_secret_file = File.join(gitlab_rails_etc_dir, 'gitlab_shell_secret')
gitlab_workhorse_sockets_directory = node['gitlab']['gitlab_workhorse']['sockets_directory']
restorecon_flags = "-v"
restorecon_flags << " -n" if dry_run
# If SELinux is enabled, make sure that OpenSSH thinks the .ssh directory and authorized_keys file of the
# git_user is valid.
selinux_code = []
selinux_code << "semanage fcontext -a -t gitlab_shell_t '#{ssh_dir}(/.*)?'"
......@@ -22,9 +24,9 @@
# If SELinux is enabled, make sure that OpenSSH thinks the .ssh directory and authorized_keys file of the
# git_user is valid.
selinux_code = []
selinux_code << "semanage fcontext -a -t gitlab_shell_t '#{ssh_dir}(/.*)?'"
selinux_code << "restorecon -R -v '#{ssh_dir}'" if File.exist?(ssh_dir)
selinux_code << "restorecon -R #{restorecon_flags} '#{ssh_dir}'" if File.exist?(ssh_dir)
[
authorized_keys,
gitlab_shell_config_file,
......@@ -34,7 +36,7 @@
selinux_code << "semanage fcontext -a -t gitlab_shell_t '#{file}'"
next unless File.exist?(file)
selinux_code << "restorecon -v '#{file}'"
selinux_code << "restorecon #{restorecon_flags} '#{file}'"
end
selinux_code.join("\n")
......
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# For testing purposes, if the first path cannot be found load the second
begin
require_relative '../../../../cookbooks/package/libraries/helpers/selinux_helper.rb'
rescue LoadError
require_relative '../../../gitlab-cookbooks/package/libraries/helpers/selinux_helper.rb'
end
module GitlabCtl
class SELinuxManager
class << self
def parse_options(args, banner)
options = { verbose: false, dry_run: false }
begin
OptionParser.new do |opts|
opts.banner = banner
opts.on('-v', '--verbose', 'Show all output.') do |v|
options[:verbose] = v
end
opts.on('-d', '--dry-run', 'Show what would change.') do |d|
options[:dry_run] = d
options[:verbose] = true
end
end.parse!(args)
rescue OptionParser::InvalidOption
args << '-h'
options = parse_options(args, banner)
end
options
end
end
end
end
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require "#{base_path}/embedded/service/omnibus-ctl/lib/gitlab_ctl/selinux"
require "#{base_path}/embedded/service/omnibus-ctl/lib/gitlab_ctl/util"
add_command_under_category('apply-sepolicy',
'SELinux Controls',
'Apply GitLab SELinux policy to managed files',
2) do
options = GitlabCtl::SELinuxManager.parse_options(ARGV, "Usage: gitlab-ctl apply-sepolicy [options]")
node_attributes = GitlabCtl::Util.get_node_attributes
result = GitlabCtl::Util.run_command(SELinuxHelper.commands(node_attributes, dry_run: options[:dry_run]))
log result.stdout if options[:verbose] && !result.stdout.empty?
rescue GitlabCtl::Errors::NodeError => e
log "Cannot apply SELinux policy and contexts. #{e}"
end
......@@ -22,13 +22,7 @@
context 'when running on selinux' do
before do
allow_any_instance_of(ShellOutHelper).to receive(:success?).with('id -Z').and_return(true)
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).with('/var/opt/gitlab/.ssh').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/.ssh/authorized_keys').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/gitlab-rails/etc/gitlab_shell_secret').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/gitlab-shell/config.yml').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/gitlab-workhorse/sockets').and_return(true)
end
let(:bash_block) { chef_run.bash('Set proper security context on ssh files for selinux') }
......@@ -31,12 +25,8 @@
end
let(:bash_block) { chef_run.bash('Set proper security context on ssh files for selinux') }
def semanage_fcontext(filename)
"semanage fcontext -a -t gitlab_shell_t '#{filename}'"
end
it 'should run the semanage bash command' do
expect(templatesymlink).to notify('bash[Set proper security context on ssh files for selinux]').delayed
end
......@@ -39,46 +29,7 @@
it 'should run the semanage bash command' do
expect(templatesymlink).to notify('bash[Set proper security context on ssh files for selinux]').delayed
end
it 'sets the security context of gitlab-shell files' do
lines = bash_block.code.split("\n")
files = %w(/var/opt/gitlab/.ssh(/.*)?
/var/opt/gitlab/.ssh/authorized_keys
/var/opt/gitlab/gitlab-shell/config.yml
/var/opt/gitlab/gitlab-rails/etc/gitlab_shell_secret
/var/opt/gitlab/gitlab-workhorse/sockets)
managed_files = files.map { |file| semanage_fcontext(file) }
expect(lines).to include(*managed_files)
expect(lines).to include("restorecon -R -v '/var/opt/gitlab/.ssh'")
expect(lines).to include("restorecon -v '/var/opt/gitlab/.ssh/authorized_keys'")
expect(lines).to include("restorecon -v '/var/opt/gitlab/gitlab-shell/config.yml'")
expect(lines).to include("restorecon -v '/var/opt/gitlab/gitlab-rails/etc/gitlab_shell_secret'")
expect(lines).to include("restorecon -v '/var/opt/gitlab/gitlab-workhorse/sockets'")
end
context 'and the user configured a custom workhorse sockets directory' do
let(:user_sockets_directory) { '/how/do/you/do' }
before do
stub_gitlab_rb(
gitlab_workhorse: {
listen_network: 'unix',
sockets_directory: user_sockets_directory
}
)
end
it 'sets the security context of a custom workhorse sockets directory' do
allow(File).to receive(:exist?).with(user_sockets_directory).and_return(true)
lines = bash_block.code.split("\n")
files = [user_sockets_directory]
managed_files = files.map { |file| semanage_fcontext(file) }
expect(lines).to include(*managed_files)
expect(lines).to include("restorecon -v '#{user_sockets_directory}'")
end
end
context 'when gitlab-rails is disabled' do
before do
stub_gitlab_rb(
......
# frozen_string_literal: true
require 'chef_helper'
RSpec.describe SELinuxHelper do
let(:chef_run) { converge_config }
context 'when building SELinux policy command strings' do
before do
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).with('/var/opt/gitlab/.ssh').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/.ssh/authorized_keys').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/gitlab-rails/etc/gitlab_shell_secret').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/gitlab-shell/config.yml').and_return(true)
allow(File).to receive(:exist?).with('/var/opt/gitlab/gitlab-workhorse/sockets').and_return(true)
end
def semanage_fcontext(filename)
"semanage fcontext -a -t gitlab_shell_t '#{filename}'"
end
using RSpec::Parameterized::TableSyntax
where(:dry_run, :restorecon_options) do
true | '-v -n'
false | '-v'
end
with_them do
let(:node) { chef_run.node }
let(:lines) { SELinuxHelper.commands(node, dry_run: dry_run) }
it 'adds the correct parameters to restorecon' do
expect(lines).to include("restorecon -R #{restorecon_options} '/var/opt/gitlab/.ssh'")
expect(lines).to include("restorecon #{restorecon_options} '/var/opt/gitlab/.ssh/authorized_keys'")
expect(lines).to include("restorecon #{restorecon_options} '/var/opt/gitlab/gitlab-shell/config.yml'")
expect(lines).to include("restorecon #{restorecon_options} '/var/opt/gitlab/gitlab-rails/etc/gitlab_shell_secret'")
expect(lines).to include("restorecon #{restorecon_options} '/var/opt/gitlab/gitlab-workhorse/sockets'")
end
it 'adds the correct SELinux file contexts' do
files = %w(/var/opt/gitlab/.ssh(/.*)?
/var/opt/gitlab/.ssh/authorized_keys
/var/opt/gitlab/gitlab-shell/config.yml
/var/opt/gitlab/gitlab-rails/etc/gitlab_shell_secret
/var/opt/gitlab/gitlab-workhorse/sockets)
managed_files = files.map { |file| semanage_fcontext(file) }
expect(lines).to include(*managed_files)
end
end
with_them do
let(:user_sockets_directory) { '/how/do/you/do' }
let(:node) { chef_run.node }
let(:lines) { SELinuxHelper.commands(node, dry_run: dry_run) }
before do
allow(Gitlab).to receive(:[]).and_call_original
stub_gitlab_rb(
gitlab_workhorse: {
listen_network: 'unix',
sockets_directory: user_sockets_directory
}
)
allow(File).to receive(:exist?).with(user_sockets_directory).and_return(true)
end
context 'when the user sets a custom workhorse sockets directory' do
it 'applies the security context to the custom workhorse sockets directory' do
files = [user_sockets_directory]
managed_files = files.map { |file| semanage_fcontext(file) }
expect(lines).to include(*managed_files)
expect(lines).to include("restorecon #{restorecon_options} '#{user_sockets_directory}'")
end
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment