Module: Jail

Defined in:
lib/cp_dep_libs.rb,
lib/containerize_me.rb

Defined Under Namespace

Classes: Config

Class Method Summary collapse

Class Method Details

.add_common_itemsObject



106
107
108
109
110
111
112
113
# File 'lib/containerize_me.rb', line 106

def add_common_items
  files = []
  common = %w(libnss libcurl)
  common.each { |lib|
    Find.find('/lib').each { |i| files << i if i =~ /#{lib}/ }
  }
  files
end

.add_user(user) ⇒ Object

In order to preserve the system’s /etc/passwd jailkit’s jk_addjailuser is avoided.

We only require that the user exists in the jail for all actions needed to host apps. Also, all other services(sshd, mysql, beanstalkd, etc) work fine using chroot with the –userspec. It’s assumed system user’s are not chrooted to a jail. A separate sshd process runs in the jail on a custom port and when a required jail user logs into that ssh instance they are confined to the jail. For this separation user’s are added to the jail by grabbing the user info from /etc/passwd and appending to @config.jail/etc/passwd.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/containerize_me.rb', line 132

def add_user(user)
  unless Jail.user_in_jail?(user) 
    system_users = File.read('/etc/passwd').split(/\n/).grep(/^#{user}/)
    raise StandardError unless system_users.length == 1
     = system_users.first.split(':')
    #Jail.cp(user_info[5])
   
    fd = File.open(@config.jail + '/etc/passwd', 'a')
    fd.puts system_users.first
    fd.close

    unless Jail.group_in_jail?([3])
      group = File.read('/etc/group').grep(/:#{[3]}:/).first
      fd = File.open(@config.jail + '/etc/group', 'a')
      fd.puts group
      fd.close
    end
  end
  true
end

.add_user_not_in_root_system(user, uid = nil) ⇒ Object

add a user to the jail that’s not in the root system’s /etc/passwd assumes uid == gid



166
167
168
169
170
171
172
173
174
175
176
# File 'lib/containerize_me.rb', line 166

def add_user_not_in_root_system(user, uid=nil)
  unless Jail.user_in_jail?(user) 
    uid ||= max_uid("#{@config.jail}/etc/passwd")+1
    fd = File.open("#{@config.jail}/etc/passwd", 'a')
    fd.puts "#{user}:x:#{uid}:#{uid}::/home/#{user}:/bin/bash"
    fd.close
    fd = File.open("#{@config.jail}/etc/group", 'a')
    fd.puts "#{user}:x:#{uid}:"
    fd.close
  end
end

.cp(item) ⇒ Object

TODO: update to use following: jk_cp takes too long when copying large directory structures. Use FileUtils.cp_r first followed by cp_dep_libs to use jk_cp to copy over deps for executable and shared object items



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/containerize_me.rb', line 84

def cp(item)
#=begin
  if File.directory?(item)
    dir = File.dirname(item)
    begin
      FileUtils.mkdir_p("#{@config.jail}#{dir}") unless File.directory?("#{@config.jail}#{dir}")
      FileUtils.cp_r(item, "#{@config.jail}#{dir}", {:remove_destination => true})#, :preserve => true})
    rescue => e
    end
    Jail.cp_dep_libs(item, @config.jail)
    err = ''
  else
#=end
    err = Jail.exec("jk_cp -o -j #{@config.jail} #{item}") 
  end
  FileUtils.clone_perms(item, @config.jail)
  if err.length != 0
    raise StandardError, "#{Constants::Errors::JK_INIT_ERROR} #{err}"
  end
  true
end

.cp_dep_libs(src, jail_dir) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
# File 'lib/cp_dep_libs.rb', line 10

def self.cp_dep_libs(src, jail_dir)
   if File.directory?(src) && File.directory?(jail_dir)
     Find.find(src) { |entry|
       next if File.directory?(entry)
       stat = File.stat(entry)
       if entry =~ /\.so/ || stat.executable?
         `jk_cp -f -j #{jail_dir} #{entry}`
       end
     }
  end
end

.createObject



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/containerize_me.rb', line 68

def create
  FileUtils.mkdir_p @config.jail unless File.directory?(@config.jail)
  raise JailKitNotFoundError, Constants::Errors::MISSING_JK unless has_jailkit?
  raise JailNotWritable, Constants::Errors::JAIL_NOT_WRITABLE unless File.writable?(@config.jail)

  err = Jail.exec("jk_init -j #{@config.jail} jk_lsh")
  if err.length != 0
    raise StandardError, "#{Constants::Errors::JK_INIT_ERROR} #{err}"
  end
  true
end

.exec(str) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/containerize_me.rb', line 53

def exec(str)
  res = '' 
  std_in, std_out, std_err = Open3::popen3(str) 
  puts std_out.read
  err = std_err.read
  err.each_line { |line|
    next if "#{line}" =~ /empty, not checked/
    res += line
  }
  res 
end

.group_in_jail?(gid) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/containerize_me.rb', line 119

def group_in_jail?(gid)
  File.read(@config.jail + '/etc/group').grep(/#{gid}:$/).first != nil ? true : false
end

.has_jailkit?Boolean

Returns:

  • (Boolean)


64
65
66
67
# File 'lib/containerize_me.rb', line 64

def has_jailkit?
  out=`which jk_init`
  out.length > 0 ? true : false
end

.max_uid(passwd_file) ⇒ Object

Raises:

  • (ArgumentError)


153
154
155
156
157
158
159
160
161
162
# File 'lib/containerize_me.rb', line 153

def max_uid(passwd_file)
  max = 0
  raise ArgumentError unless File.exists?(passwd_file)
  File.readlines(passwd_file).each { |l|
    pass_entry = l.split(':')
    next if pass_entry[2].to_i >= 65534
    max = pass_entry[2].to_i if pass_entry[2].to_i > max
  }
  max
end

.performObject



291
292
293
294
295
296
# File 'lib/containerize_me.rb', line 291

def perform
  if Jail.create
    @config.dep_order.reverse.each { |i| process(i) }
    process(@config)
  end
end

.process(cfg) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/containerize_me.rb', line 178

def process(cfg)
  if cfg.kind_of?(Jail::Config)
    cfg = @config.cfg
  end
  files = []
  files += cfg[:system_binaries] if cfg[:system_binaries].kind_of?(Array)
  files +=  cfg[:other_files] if cfg[:other_files].kind_of?(Array)
  files +=  cfg[:copy_items] if cfg[:copy_items].kind_of?(Array)
  files += Jail.add_common_items
  files.each { |file| Jail.cp(file) } 
  if cfg.has_key?(:users)
    cfg[:users].each { |user| Jail.add_user(user) } if cfg[:users].kind_of?(Array)
  end

  if cfg.has_key?(:add_non_system_users)
    if cfg[:add_non_system_users].kind_of?(Array)
      cfg[:add_non_system_users].each { |user|
        add_user_not_in_root_system(user)
        user_home = "#{@config.jail}/home/#{user}"
        FileUtils.mkdir_p(user_home) unless File.directory?(user_home)
        `chroot #{@config.jail} chown #{user} #{user_home}`
      }
    end
  end

  if cfg.has_key?(:mkdir)
    if cfg[:mkdir].kind_of?(Array)
      cfg[:mkdir].each { |dir|
        d = "#{@config.jail}#{dir[:item]}"
        FileUtils.mkdir_p d unless File.directory?(d)
        if dir[:user].length > 0 && dir[:group].length > 0
          # in case the user exists in the jail but not system
          #`chroot #{@config.jail} chown #{dir[:user]}:#{dir[:group]} #{dir[:item]}`
          FileUtils.chown(dir[:user], dir[:group], d)
          FileUtils.chmod(dir[:mode], d) if dir.has_key?(:mode)
        end
      }
    
    end
  end

  if cfg.has_key?(:symlinks)
    if cfg[:symlinks].kind_of?(Array)
      cfg[:symlinks].each { |i|
        begin
          i[:force] ||= nil
          unless i.has_key?(:source) && i.has_key?(:destination)
            raise StandardError, ":source and :destination must be provided when creating a symlink" 
          end
          unless File.exists?i[:source]
            raise StandardError, ":source file/directory not found"
          end
          if i[:force]
            FileUtils.ln_sf(i[:source], "#{@config.jail}/#{i[:destination]}")
          else
            FileUtils.ln_s(i[:source], "#{@config.jail}/#{i[:destination]}")
          end
        rescue => e
          p "issue creating symlink: #{e.inspect}"
        end 
      }
    end
  end

  if cfg.has_key?(:chown)
    if cfg[:chown].kind_of?(Array)
      cfg[:chown].each { |i|
        begin
          FileUtils.chown_R(i[:user], i[:group], "#{@config.jail}#{i[:item]}") if File.exists?("#{@config.jail}#{i[:item]}")
        rescue => e
          p "issue chown: #{e.inspect}"
        end 
      }
    end 
  end 

  if cfg.has_key?(:chmod)
    if cfg[:chmod].kind_of?(Array)
      cfg[:chmod].each { |i|
        begin
          FileUtils.chmod(i[:mode], "#{@config.jail}#{i[:item]}") if File.exists?("#{@config.jail}#{i[:item]}")
        rescue => e
          p "issue chown: #{e.inspect}"
        end 
      }
    end 
  end 
=begin
  if cfg.has_key?(:sudo)
    if cfg[:sudo].kind_of?(Array)
      FileUtils.chmod(0600, '/etc/sudoers')
      fd = File.open("#{@config.jail}/etc/sudoers', 'w+')
      cfg[:sudo].each { |i|
        begin
          if Jail.user_in_jail?(i[:user])
            if i[:commands].kind_of?(Array)
             fd.puts "#{i[:user]} ALL=NOPASSWD:  #{i[:commands].join(',')}"
            end
          end
        rescue => e
          p "issue chown: #{e.inspect}"
        ensure
          fd.close
          FileUtils.chmod(0400, '/etc/sudoers')
        end 
      }
    end 
  end 
=end


end

.user_in_jail?(user) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/containerize_me.rb', line 115

def user_in_jail?(user)
  File.read(@config.jail + '/etc/passwd').grep(/^#{user}/).first != nil ? true : false
end