Class: OsCtld::AppArmor
- Inherits:
-
Object
- Object
- OsCtld::AppArmor
- Extended by:
- OsCtl::Lib::Utils::System
- Includes:
- OsCtl::Lib::Utils::Log, OsCtl::Lib::Utils::System
- Defined in:
- lib/osctld/apparmor.rb
Constant Summary collapse
- PATHS =
Paths where ‘apparmor_parser` searches for configuration files
[RunState::APPARMOR_DIR].freeze
Instance Attribute Summary collapse
-
#ct ⇒ Object
readonly
protected
Returns the value of attribute ct.
Class Method Summary collapse
-
.apparmor_parser(pool, cmd, profiles, opts = {}) ⇒ Object
Call apparmor_parser.
- .assets(add, pool) ⇒ Object
-
.cache_dir(pool) ⇒ Object
Per-pool runstate directory with profile cache.
- .enabled? ⇒ Boolean
-
.profile_dir(pool) ⇒ Object
Per-pool runstate directory with profiles.
-
.setup ⇒ Object
Prepare shared files in ‘/run/osctl`.
-
.setup_pool(pool) ⇒ Object
Load profiles of running containers from ‘pool`.
Instance Method Summary collapse
- #apparmor_parser(cmd, opts = {}) ⇒ Object protected
- #cache_dir ⇒ Object protected
-
#create_namespace ⇒ Object
Create an AppArmor namespace for the container.
-
#destroy_namespace ⇒ Object
Destroy the container’s AppArmor namespace.
-
#destroy_profile ⇒ Object
Remove the container’s profile from the kernel and remove it from cache.
- #dup(new_ct) ⇒ Object
-
#generate_profile ⇒ Object
Generate AppArmor profile for the container.
-
#initialize(ct) ⇒ AppArmor
constructor
A new instance of AppArmor.
-
#load_profile ⇒ Object
Load the container’s profile into the kernel.
- #namespace ⇒ Object
- #namespace_path ⇒ Object protected
- #namespace_profile_name ⇒ Object
- #profile_name ⇒ Object
- #profile_path ⇒ Object
-
#setup ⇒ Object
Generate container profile, load it and create a namespace.
-
#unload_profile ⇒ Object
Remove the container’s profile from the kernel.
Constructor Details
#initialize(ct) ⇒ AppArmor
Returns a new instance of AppArmor.
105 106 107 |
# File 'lib/osctld/apparmor.rb', line 105 def initialize(ct) @ct = ct end |
Instance Attribute Details
#ct ⇒ Object (readonly, protected)
Returns the value of attribute ct.
193 194 195 |
# File 'lib/osctld/apparmor.rb', line 193 def ct @ct end |
Class Method Details
.apparmor_parser(pool, cmd, profiles, opts = {}) ⇒ Object
Call apparmor_parser
96 97 98 99 100 101 102 |
# File 'lib/osctld/apparmor.rb', line 96 def self.apparmor_parser(pool, cmd, profiles, opts = {}) syscmd( "apparmor_parser -#{cmd} -W -v #{PATHS.map { |v| "-I #{v}" }.join(' ')} " \ "-L #{cache_dir(pool)} #{profiles.join(' ')}", opts ) end |
.assets(add, pool) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/osctld/apparmor.rb', line 74 def self.assets(add, pool) add.directory( profile_dir(pool), desc: 'Per-container AppArmor profiles', user: 0, group: 0, mode: 0o700 ) add.directory( profile_dir(pool), desc: 'Cache for apparmor_parser', user: 0, group: 0, mode: 0o700 ) end |
.cache_dir(pool) ⇒ Object
Per-pool runstate directory with profile cache
70 71 72 |
# File 'lib/osctld/apparmor.rb', line 70 def self.cache_dir(pool) File.join(pool.apparmor_dir, 'cache') end |
.enabled? ⇒ Boolean
13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/osctld/apparmor.rb', line 13 def self.enabled? if @enabled.nil? begin @enabled = Daemon.get.config.apparmor_paths.any? \ && Dir.exist?('/sys/kernel/security/apparmor') \ && File.read('/sys/module/apparmor/parameters/enabled').strip.downcase == 'y' rescue Errno::ENOENT @enabled = false end else @enabled end end |
.profile_dir(pool) ⇒ Object
Per-pool runstate directory with profiles
65 66 67 |
# File 'lib/osctld/apparmor.rb', line 65 def self.profile_dir(pool) File.join(pool.apparmor_dir, 'profiles') end |
.setup ⇒ Object
Prepare shared files in ‘/run/osctl`
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/osctld/apparmor.rb', line 28 def self.setup PATHS.concat(Daemon.get.config.apparmor_paths) base = File.join(RunState::APPARMOR_DIR, 'osctl') features = File.join(base, 'features') [base, features].each do |dir| FileUtils.mkdir_p(dir, mode: 0o755) end ErbTemplate.render_to( 'apparmor/features/nesting', {}, File.join(features, 'nesting') ) end |
.setup_pool(pool) ⇒ Object
Load profiles of running containers from ‘pool`
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/osctld/apparmor.rb', line 47 def self.setup_pool(pool) [profile_dir(pool), cache_dir(pool)].each do |dir| FileUtils.mkdir_p(dir, mode: 0o700) end cts = DB::Containers.get.select do |ct| next(false) if ct.pool != pool || !ct.running? ct.apparmor.generate_profile true end return unless cts.any? apparmor_parser(pool, 'r', cts.map { |ct| ct.apparmor.profile_path }) end |
Instance Method Details
#apparmor_parser(cmd, opts = {}) ⇒ Object (protected)
203 204 205 |
# File 'lib/osctld/apparmor.rb', line 203 def apparmor_parser(cmd, opts = {}) self.class.apparmor_parser(ct.pool, cmd, [profile_path], opts) end |
#cache_dir ⇒ Object (protected)
199 200 201 |
# File 'lib/osctld/apparmor.rb', line 199 def cache_dir self.class.cache_dir(ct.pool) end |
#create_namespace ⇒ Object
Create an AppArmor namespace for the container
156 157 158 159 |
# File 'lib/osctld/apparmor.rb', line 156 def create_namespace path = namespace_path FileUtils.mkdir_p(path) end |
#destroy_namespace ⇒ Object
Destroy the container’s AppArmor namespace
162 163 164 165 |
# File 'lib/osctld/apparmor.rb', line 162 def destroy_namespace path = namespace_path FileUtils.rm_f(path) end |
#destroy_profile ⇒ Object
Remove the container’s profile from the kernel and remove it from cache
144 145 146 147 148 149 150 151 152 153 |
# File 'lib/osctld/apparmor.rb', line 144 def destroy_profile unload_profile if File.exist?(profile_path) begin cached = File.join(cache_dir, profile_name) File.unlink(cached) rescue Errno::ENOENT # ignore end end |
#dup(new_ct) ⇒ Object
185 186 187 188 189 |
# File 'lib/osctld/apparmor.rb', line 185 def dup(new_ct) ret = super() ret.instance_variable_set('@ct', new_ct) ret end |
#generate_profile ⇒ Object
Generate AppArmor profile for the container
The profile is generated only if it has been changed to let ‘apparmor_parser` use cached profiles for faster container startup times.
120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/osctld/apparmor.rb', line 120 def generate_profile ErbTemplate.render_to_if_changed('apparmor/profile', { name: profile_name, namespace:, ct:, all_combinations_of: lambda do |arr| ret = [] arr.count.times { |i| ret.concat(arr.combination(i + 1).to_a) } ret end }, profile_path) end |
#load_profile ⇒ Object
Load the container’s profile into the kernel
134 135 136 |
# File 'lib/osctld/apparmor.rb', line 134 def load_profile apparmor_parser('r') end |
#namespace ⇒ Object
175 176 177 178 179 |
# File 'lib/osctld/apparmor.rb', line 175 def namespace # Ubuntu's AppArmor service initializes profiles only when in a namespace # beginning with `lxd-` or `lxc-`, so we have to use the prefix as well. "lxc-#{profile_name}" end |
#namespace_path ⇒ Object (protected)
195 196 197 |
# File 'lib/osctld/apparmor.rb', line 195 def namespace_path File.join('/sys/kernel/security/apparmor/policy/namespaces', namespace) end |
#namespace_profile_name ⇒ Object
181 182 183 |
# File 'lib/osctld/apparmor.rb', line 181 def namespace_profile_name "#{profile_name}//&:#{namespace}:" end |
#profile_name ⇒ Object
167 168 169 |
# File 'lib/osctld/apparmor.rb', line 167 def profile_name "ct-#{ct.pool.name}-#{ct.id}" end |
#profile_path ⇒ Object
171 172 173 |
# File 'lib/osctld/apparmor.rb', line 171 def profile_path File.join(self.class.profile_dir(ct.pool), profile_name) end |
#setup ⇒ Object
Generate container profile, load it and create a namespace
110 111 112 113 114 |
# File 'lib/osctld/apparmor.rb', line 110 def setup generate_profile load_profile create_namespace end |
#unload_profile ⇒ Object
Remove the container’s profile from the kernel
139 140 141 |
# File 'lib/osctld/apparmor.rb', line 139 def unload_profile apparmor_parser('R', valid_rcs: [254]) end |