class OpenShift::Runtime::ApplicationContainerExt::SecureShell::AuthorizedKeysFile

Manage a user (gear/container) SSH #authorized_keys file and entries

Attributes

container[R]
filename[R]
group[RW]
lockfile[RW]
mode[RW]
owner[RW]
username[R]

Public Class Methods

new(container, filename=nil) click to toggle source
# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 21
def initialize(container, filename=nil)
  @container = container
  @username = container.uuid
  @filename = filename || 
    @container.container_dir + "/.ssh/authorized_keys"

  # override for testing
  user = Etc.getpwnam('root')
  @owner = user.uid # root
  begin
    @group = Etc.getpwnam(@username).gid
  rescue ArgumentError => e
    @group = @@default_group
  end
  @mode = @@default_mode

  @lockfile = "/var/lock/oo-modify-ssh-keys.#{@username}"
end

Public Instance Methods

add_key(key_string, key_type=nil, comment=nil) click to toggle source

Bodies from environment.rb globals

Public: Append an SSH key to a users #authorized_keys file

key_string - The String value of the ssh key. key_type - The String value of the key type ssh-(rsa|dss)). comment - The String value of the comment to append to the key.

Examples

add_ssh_key('AAAAB3NzaC1yc2EAAAADAQABAAABAQDE0DfenPIHn5Bq/...',
            'ssh-rsa',
            'example@example.com')
# => nil

Returns nil on Success or raises on Failure

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 61
def add_key(key_string, key_type=nil, comment=nil)
  comment = "" unless comment

  modify do |keys|
    keys[key_id(comment)] = key_entry(key_string, key_type, comment)
  end

end
authorized_keys() click to toggle source
# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 40
def authorized_keys
  modify
end
remove_key(key_string, key_type=nil, comment=nil) click to toggle source

Public: Remove an SSH key from a users #authorized_keys file

key_string - The String value of the ssh key. key_type - The String value of the key type ssh-(rsa|dss)). comment - The String value of the comment to append to the key.

Examples

remove_ssh_key('AAAAB3NzaC1yc2EAAAADAQABAAABAQDE0DfenPIHn5Bq/...',
               'ssh-rsa',
               'example@example.com')
# => nil

Returns nil on Success or raises on Failure

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 85
def remove_key(key_string, key_type=nil, comment=nil)
  modify do |keys|
    if comment
      keys.delete_if{ |k, v| v.end_with?(key_id(comment)) }
    else
      keys.delete_if{ |k,v| v.include?(key_string) }
    end
  end
end
replace_keys(new_keys) click to toggle source

Public: Replace all of the SSH #authorized_keys file entries

new_keys - an Array of Hashes, each containing

key => String,
type => String
comment => String

Examples:

k = [
    {'key' => 'AAA...', 
     'type' => 'ssh-rsa', 
     'comment' => 'String'
    },
    {'key' => 'bar...',
     'type' => 'ssh-rsa',
     'comment' => 'more'
    },
    {'key' => 'AAA...', 
     'type' => 'ssh-rsa',
     'comment' => 'String'},
    ]
replace_keys(k)

Returns: nil on Success

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 120
def replace_keys(new_keys)

  modify do |keys|
    # remove all keys
    keys.delete_if{ |k, v| true }

    # add the new keys in
    new_keys.each do |key|
      id = key_id(key['comment'])
      entry = key_entry(key['key'], key['type'], key['comment'])
      keys[id] = entry
    end
  end
      
  # set/reset the SELinux context for the .ssh directory
  ssh_dir = PathUtils.join(@container.container_dir, "/.ssh")
  cmd = "restorecon -R #{ssh_dir}"
  ::OpenShift::Runtime::Utils::oo_spawn(cmd)

end

Private Instance Methods

clever_validate_keys(ssh_keys) click to toggle source

This version does exactly the same as the previous one but uses only lazy-evaluation boolean logic and map-reduce to collect the value for each entry

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 169
def clever_validate_keys(ssh_keys)
  ssh_keys.is_a? Array and
  # check each entry
  ssh_keys.map { |entry|
    not entry.nil? and
    entry['key'].is_a? String and entry['key'].length > 0 and
    entry['type'].is_a? String and entry['type'].length > 0 and
    (entry['comment'].nil? or 
     (entry['comment'].is_a? String and entry['comment'].length > 0))
  # any false results invalidates the whole set
  }.reduce(:&)
end
key_entry(key_string, key_type, comment) click to toggle source

Create a single SSH Authorized keys entry

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 189
def key_entry(key_string, key_type, comment)
  shell       = @container.container_plugin.gear_shell || "/bin/bash"
  command   = "command=\"#{shell}\",no-X11-forwarding"
  [command, key_type, key_string, key_id(comment)].join(' ')
end
key_id(comment) click to toggle source

This value is used both as a lookup id for add/remove operations and as the actual comment field of the authorized key line

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 184
def key_id(comment)
  "OPENSHIFT-#{@container.uuid}-#{comment}"
end
modify() { |keys| ... } click to toggle source

private: Modify ssh #authorized_keys file

@yields [Hash] authorized keys with the comment field as the key which will save if modified. @return [Hash] authorized keys with the comment field as the key private: Modify ssh #authorized_keys file

@yields [Hash] authorized keys with the comment field as the key which will save if modified. @return [Hash] authorized keys with the comment field as the key

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 203
def modify
  authorized_keys_file = @filename
  keys = Hash.new

  @@mutex.synchronize do
    File.open(@lockfile, File::RDWR|File::CREAT|File::TRUNC, 0600) do | lock |
      lock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      lock.flock(File::LOCK_EX)
      begin
        File.open(authorized_keys_file, File::RDWR|File::CREAT, @mode) do |file|
          file.each_line do |line|
            begin
              keys[line.split[-1].chomp] = line.chomp
            rescue
            end
          end

          if block_given?
            old_keys = keys.clone

            yield keys

            if old_keys != keys
              file.seek(0, IO::SEEK_SET)
              file.write(keys.values.join("\n")+"\n")
              file.truncate(file.tell)
            end
          end
          file.close
        end
        @container.set_ro_permission(authorized_keys_file)
        ::OpenShift::Runtime::Utils::oo_spawn("restorecon #{authorized_keys_file}")
      ensure
        lock.flock(File::LOCK_UN)
      end
    end
  end
  keys
end
validate_keys(ssh_keys) click to toggle source

validate the ssh keys to check for the required attributes

ssh_keys must be an array ssh_keys must be a hash ssh_keys['key'] must be a non-empty string ssh_keys['type'] must be a non-empty string ssh_keys['comment'] must be nil or a non-empty string

# File lib/openshift-origin-node/model/application_container_ext/ssh_authorized_keys.rb, line 151
def validate_keys(ssh_keys)
  return false unless ssh_keys.is_a? Array
  ssh_keys.each do |entry|
    return false if entry.nil?
    return false if not 
      (entry['key'].is_a? String and entry['key'].length > 0)
    return false if not
      (entry['type'].is_a? String and entry['type'].length > 0)
    return false if not
      (entry['comment'].nil? or 
      (entry['comment'].is_a? String and entry['comment'].length > 0))
  end
  true
end