diff --git a/library/add_host b/library/add_host deleted file mode 100644 index fe9780e921..0000000000 --- a/library/add_host +++ /dev/null @@ -1,23 +0,0 @@ -# -*- mode: python -*- - -DOCUMENTATION = ''' ---- -module: add_host -short_description: add a host (and alternatively a group) to the ansible-playbook in-memory inventory -description: - - Use variables to create new hosts and groups in inventory for use in later plays of the same playbook -version_added: 0.9 -options: - hostname: - description: - - The hostname/ip of the host to add to the inventory - required: true - groupname: - description: - - The groupname to add the hostname to. - required: false -author: Seth Vidal -examples: - - description: add host to group 'just_created' - code: add_host hostname=${ip_from_ec2create} groupname=just_created -''' \ No newline at end of file diff --git a/library/authorized_key b/library/authorized_key new file mode 100644 index 0000000000..f936e20c81 --- /dev/null +++ b/library/authorized_key @@ -0,0 +1,187 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Ansible module to add authorized_keys for ssh logins. +(c) 2012, Brad Olson + +This file is part of Ansible + +Ansible is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Ansible is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Ansible. If not, see . +""" + +DOCUMENTATION = ''' +--- +module: authorized_key +short_description: Adds or removes an SSH authorized key +description: + - Adds or removes an SSH authorized key for a user from a remote host. +version_added: "0.5" +options: + user: + description: + - Name of the user who should have access to the remote host + required: true + default: null + aliases: [] + key: + description: + - the SSH public key, as a string + required: true + default: null + state: + description: + - whether the given key should or should not be in the file + required: false + choices: [ "present", "absent" ] + default: "present" +examples: + - code: 'authorized_key: user=charlie key="ssh-dss ASDF1234L+8BTwaRYr/rycsBF1D8e5pTxEsXHQs4iq+mZdyWqlW++L6pMiam1A8yweP+rKtgjK2httVS6GigVsuWWfOd7/sdWippefq74nppVUELHPKkaIOjJNN1zUHFoL/YMwAAAEBALnAsQN10TNGsRDe5arBsW8cTOjqLyYBcIqgPYTZW8zENErFxt7ij3fW3Jh/sCpnmy8rkS7FyK8ULX0PEy/2yDx8/5rXgMIICbRH/XaBy9Ud5bRBFVkEDu/r+rXP33wFPHjWjwvHAtfci1NRBAudQI/98DbcGQw5HmE89CjgZRo5ktkC5yu/8agEPocVjdHyZr7PaHfxZGUDGKtGRL2QzRYukCmWo1cZbMBHcI5FzImvTHS9/8B3SATjXMPgbfBuEeBwuBK5EjL+CtHY5bWs9kmYjmeo0KfUMH8hY4MAXDoKhQ7DhBPIrcjS5jPtoGxIREZjba67r6/P2XKXaCZH6Fc= charlie@example.org 2011-01-17"' + description: "Example from Ansible Playbooks" + - code: "authorized_key: user=charlie key='$FILE(/home/charlie/.ssh/id_rsa.pub)'" + description: "Shorthand available in Ansible 0.8 and later" +author: Brad Olson +''' + +# Makes sure the public key line is present or absent in the user's .ssh/authorized_keys. +# +# Arguments +# ========= +# user = username +# key = line to add to authorized_keys for user +# state = absent|present (default: present) +# +# see example in examples/playbooks + +import sys +import os +import pwd +import os.path +import tempfile +import shutil + +def keyfile(module, user, write=False): + """ + Calculate name of authorized keys file, optionally creating the + directories and file, properly setting permissions. + + :param str user: name of user in passwd file + :param bool write: if True, write changes to authorized_keys file (creating directories if needed) + :return: full path string to authorized_keys for user + """ + + try: + user_entry = pwd.getpwnam(user) + except KeyError, e: + module.fail_json(msg="Failed to lookup user %s: %s" % (user, str(e))) + homedir = user_entry.pw_dir + sshdir = os.path.join(homedir, ".ssh") + keysfile = os.path.join(sshdir, "authorized_keys") + + if not write: + return keysfile + + uid = user_entry.pw_uid + gid = user_entry.pw_gid + + if not os.path.exists(sshdir): + os.mkdir(sshdir, 0700) + if module.selinux_enabled(): + module.set_default_selinux_context(sshdir, False) + os.chown(sshdir, uid, gid) + os.chmod(sshdir, 0700) + + if not os.path.exists( keysfile): + try: + f = open(keysfile, "w") #touches file so we can set ownership and perms + finally: + f.close() + if module.selinux_enabled(): + module.set_default_selinux_context(keysfile, False) + + os.chown(keysfile, uid, gid) + os.chmod(keysfile, 0600) + return keysfile + +def readkeys(filename): + + if not os.path.isfile(filename): + return [] + f = open(filename) + keys = [line.rstrip() for line in f.readlines()] + f.close() + return keys + +def writekeys(module, filename, keys): + + fd, tmp_path = tempfile.mkstemp('', 'tmp', os.path.dirname(filename)) + f = open(tmp_path,"w") + try: + f.writelines( (key + "\n" for key in keys) ) + except IOError, e: + module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, str(e))) + f.close() + module.atomic_replace(tmp_path, filename) + +def enforce_state(module, params): + """ + Add or remove key. + """ + + user = params["user"] + key = params["key"] + state = params.get("state", "present") + + key = key.split('\n') + + # check current state -- just get the filename, don't create file + params["keyfile"] = keyfile(module, user, write=False) + keys = readkeys(params["keyfile"]) + + # Check our new keys, if any of them exist we'll continue. + for new_key in key: + present = new_key in keys + # handle idempotent state=present + if state=="present": + if present: + continue + keys.append(new_key) + writekeys(module, keyfile(module, user,write=True), keys) + params['changed'] = True + + elif state=="absent": + if not present: + continue + keys.remove(new_key) + writekeys(module, keyfile(module, user,write=True), keys) + params['changed'] = True + + return params + +def main(): + + module = AnsibleModule( + argument_spec = dict( + user = dict(required=True), + key = dict(required=True), + state = dict(default='present', choices=['absent','present']) + ) + ) + + results = enforce_state(module, module.params) + module.exit_json(**results) + +# this is magic, see lib/ansible/module_common.py +#<> +main()