#!/usr/bin/python3 # Copyright 2018, Red Hat, Inc. # # 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. from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = { 'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community' } DOCUMENTATION = ''' --- module: ceph_key author: Sebastien Han short_description: Manage Cephx key(s) version_added: "2.6" description: - Manage CephX creation, deletion and updates. It can also list and get information about keyring(s). options: cluster: description: - The ceph cluster name. required: false default: ceph name: description: - name of the CephX key required: true user: description: - entity used to perform operation. It corresponds to the -n option (--name) required: false user_key: description: - the path to the keyring corresponding to the user being used. It corresponds to the -k option (--keyring) state: description: - If 'present' is used, the module creates a keyring with the associated capabilities. If 'present' is used and a secret is provided the module will always add the key. Which means it will update the keyring if the secret changes, the same goes for the capabilities. If 'absent' is used, the module will simply delete the keyring. If 'list' is used, the module will list all the keys and will return a json output. If 'info' is used, the module will return in a json format the description of a given keyring. required: true choices: ['present', 'absent', 'list', 'info'] default: list caps: description: - CephX key capabilities default: None required: false secret: description: - keyring's secret value required: false default: None import_key: description: - Wether or not to import the created keyring into Ceph. This can be useful for someone that only wants to generate keyrings but not add them into Ceph. required: false default: True dest: description: - Destination to write the keyring, can a file or a directory required: false default: /etc/ceph/ fetch_initial_keys: description: - Fetch client.admin and bootstrap key. This is only needed for Nautilus and above. Writes down to the filesystem the initial keys generated by the monitor. # noqa E501 This command can ONLY run from a monitor node. required: false default: false ''' EXAMPLES = ''' keys_to_create: - { name: client.key, key: "AQAin8tUUK84ExAA/QgBtI7gEMWdmnvKBzlXdQ==", caps: { mon: "allow rwx", mds: "allow *" } , mode: "0600" } # noqa e501 - { name: client.cle, caps: { mon: "allow r", osd: "allow *" } , mode: "0600" } # noqa e501 caps: mon: "allow rwx" mds: "allow *" - name: create ceph admin key ceph_key: name: client.admin state: present secret: AQAin8tU2DsKFBAAFIAzVTzkL3+gtAjjpQiomw== caps: mon: allow * osd: allow * mgr: allow * mds: allow mode: 0400 import_key: False - name: create monitor initial keyring ceph_key: name: mon. state: present secret: AQAin8tUMICVFBAALRHNrV0Z4MXupRw4v9JQ6Q== caps: mon: allow * dest: "/var/lib/ceph/tmp/" import_key: False - name: create cephx key ceph_key: name: "{{ keys_to_create }}" user: client.bootstrap-rgw user_key: /var/lib/ceph/bootstrap-rgw/ceph.keyring state: present caps: "{{ caps }}" - name: create cephx key but don't import it in Ceph ceph_key: name: "{{ keys_to_create }}" state: present caps: "{{ caps }}" import_key: False - name: delete cephx key ceph_key: name: "my_key" state: absent - name: info cephx key ceph_key: name: "my_key"" state: info - name: list cephx keys ceph_key: state: list - name: fetch cephx keys ceph_key: state: fetch_initial_keys ''' RETURN = '''# ''' from ansible.module_utils.basic import AnsibleModule # noqa E402 import datetime # noqa E402 import grp # noqa E402 import json # noqa E402 import os # noqa E402 import pwd # noqa E402 import stat # noqa E402 import struct # noqa E402 import time # noqa E402 import base64 # noqa E402 import socket # noqa E402 CEPH_INITIAL_KEYS = ['client.admin', 'client.bootstrap-mds', 'client.bootstrap-mgr', # noqa E501 'client.bootstrap-osd', 'client.bootstrap-rbd', 'client.bootstrap-rbd-mirror', 'client.bootstrap-rgw'] # noqa E501 def str_to_bool(val): try: val = val.lower() except AttributeError: val = str(val).lower() if val == 'true': return True elif val == 'false': return False else: raise ValueError("Invalid input value: %s" % val) def fatal(message, module): ''' Report a fatal error and exit ''' if module: module.fail_json(msg=message, rc=1) else: raise(Exception(message)) def container_exec(binary, container_image): ''' Build the docker CLI to run a command inside a container ''' container_binary = os.getenv('CEPH_CONTAINER_BINARY') command_exec = [container_binary, 'run', '--rm', '--net=host', '-v', '/etc/ceph:/etc/ceph:z', '-v', '/var/lib/ceph/:/var/lib/ceph/:z', '-v', '/var/log/ceph/:/var/log/ceph/:z', '--entrypoint=' + binary, container_image] return command_exec def is_containerized(): ''' Check if we are running on a containerized cluster ''' if 'CEPH_CONTAINER_IMAGE' in os.environ: container_image = os.getenv('CEPH_CONTAINER_IMAGE') else: container_image = None return container_image def generate_secret(): ''' Generate a CephX secret ''' key = os.urandom(16) header = struct.pack('