def update(branch, repo): ''' Execute an update for the configured git fileserver backend for Pillar CLI Example: .. code-block:: bash salt-run git_pillar.update branch='branch' repo='location' ''' for opts_dict in __opts__.get('ext_pillar', []): parts = opts_dict.get('git', '').split() if len(parts) >= 2 and parts[:2] == [branch, repo]: salt.pillar.git_pillar.GitPillar(branch, repo, __opts__).update() break else: raise SaltRunnerError('git repo/branch not found in ext_pillar config')
def gen_csr( minion_id, dns_name, organization_id, ou_name=None, key_len=2048, shatype="sha256", password=None, ): """ CLI Example: .. code-block:: bash salt-run digicert.gen_csr <minion_id> <dns_name> """ org_details = get_org_details(organization_id) if "error" in org_details: raise SaltRunnerError( "Problem getting organization details for organization_id={0} ({1})" .format(organization_id, org_details["error"])) if org_details["dict"].get("status", "active") == "inactive": raise SaltRunnerError( "Organization with organization_id={0} is marked inactive".format( organization_id)) tmpdir = tempfile.mkdtemp() os.chmod(tmpdir, 0o700) bank = "digicert/domains" cache = salt.cache.Cache(__opts__, syspaths.CACHE_DIR) data = cache.fetch(bank, dns_name) if data is None: data = {} if "private_key" not in data: data["private_key"] = gen_key(minion_id, dns_name, password, key_len=key_len) tmppriv = "{0}/priv".format(tmpdir) tmpcsr = "{0}/csr".format(tmpdir) with salt.utils.files.fopen(tmppriv, "w") as if_: if_.write(salt.utils.stringutils.to_str(data["private_key"])) subject = "/C={0}/ST={1}/L={2}/O={3}".format( org_details["dict"]["country"], org_details["dict"]["state"], org_details["dict"]["city"], org_details["dict"]["display_name"], ) if ou_name: subject = subject + "/OU={0}".format(ou_name) subject = subject + "/CN={0}".format(dns_name) cmd = "openssl req -new -{0} -key {1} -out {2} -subj '{3}'".format( shatype, tmppriv, tmpcsr, subject) output = __salt__["salt.cmd"]("cmd.run", cmd) if "problems making Certificate Request" in output: raise CommandExecutionError( "There was a problem generating the CSR. Please ensure that you " "have a valid Organization established inside CertCentral") with salt.utils.files.fopen(tmpcsr, "r") as of_: csr = salt.utils.stringutils.to_unicode(of_.read()) data["minion_id"] = minion_id data["csr"] = csr cache.store(bank, dns_name, data) return csr
def order_certificate( minion_id, common_name, organization_id, validity_years, cert_key_passphrase=None, signature_hash=None, key_len=2048, dns_names=None, organization_units=None, server_platform=None, custom_expiration_date=None, comments=None, disable_renewal_notifications=False, product_type_hint=None, renewal_of_order_id=None, ): """ Order a certificate. Requires that an Organization has been created inside Digicert's CertCentral. See here for API documentation: https://www.digicert.com/services/v2/documentation/order/order-ssl-determinator CLI Example: .. code-block:: bash salt-run digicert.order_certificate my_minionid my.domain.com 10 \ 3 signature_hash=sha256 \ dns_names=['this.domain.com', 'that.domain.com'] \ organization_units='My Domain Org Unit' \ comments='Comment goes here for the approver' This runner can also be used to renew a certificate by passing `renewal_of_order_id`. Previous order details can be retrieved with digicertapi.list_orders. """ if dns_names and isinstance(dns_names, six.string_types): dns_names = [dns_names] if dns_names and not isinstance(dns_names, collections.Sequence): raise SaltRunnerError( "order_certificate needs a single dns_name, or an array of dns_names." ) certificate = {"common_name": common_name} certificate["dns_names"] = dns_names if signature_hash: certificate["signature_hash"] = signature_hash else: certificate["signature_hash"] = __opts__.get("digicert", {}).get( "shatype", "sha256") body = {} if organization_units and isinstance(organization_units, six.string_types): organization_units = [organization_units] if organization_units and not isinstance(organization_units, collections.Sequence): raise SaltRunnerError("Organization_units is not a valid data type.") if organization_units: certificate["organization_units"] = organization_units if organization_units: # Currently the Digicert API requires organization units to be an array # but only pays attention to the first one. csr = gen_csr( minion_id, common_name, organization_id, ou_name=organization_units[0], shatype=certificate["signature_hash"], key_len=key_len, password=cert_key_passphrase, ) else: csr = gen_csr( minion_id, common_name, organization_id, shatype=certificate["signature_hash"], key_len=key_len, password=cert_key_passphrase, ) certificate["csr"] = csr if server_platform: certificate["server_platform"]["id"] = server_platform body["organization"] = {"id": organization_id} if custom_expiration_date: body["custom_expiration_date"] = custom_expiration_date if validity_years: body["validity_years"] = validity_years if comments: body["comments"] = comments body["disable_renewal_notifications"] = disable_renewal_notifications if product_type_hint: body["product"] = {"type_hint": product_type_hint} if renewal_of_order_id: body["renewal_of_order_id"] = renewal_of_order_id body["certificate"] = certificate encoded_body = salt.utils.json.dumps(body) qdata = salt.utils.http.query( "{0}/order/certificate/ssl".format(_base_url()), method="POST", data=encoded_body, decode=True, decode_type="json", header_dict={ "X-DC-DEVKEY": _api_key(), "Content-Type": "application/json" }, raise_error=False, ) if "errors" not in qdata["dict"]: bank = "digicert/domains" cache = salt.cache.Cache(__opts__, syspaths.CACHE_DIR) data = cache.fetch(bank, common_name) if data is None: data = {} data.update({ "minion_id": minion_id, "order_id": qdata["dict"]["requests"][0]["id"], "csr": csr, }) cache.store(bank, common_name, data) _id_map(minion_id, common_name) return {"order": qdata["dict"]}
def update(branch=None, repo=None): ''' .. versionadded:: 2014.1.0 .. versionchanged:: 2015.8.4 This runner function now supports the :ref:`git_pillar configuration schema <git-pillar-configuration>` introduced in 2015.8.0. Additionally, the branch and repo can now be omitted to update all git_pillar remotes. The return data has also changed to a dictionary. The values will be ``True`` only if new commits were fetched, and ``False`` if there were errors or no new commits were fetched. .. versionchanged:: 2018.3.0 The return for a given git_pillar remote will now be ``None`` when no changes were fetched. ``False`` now is reserved only for instances in which there were errors. Fetch one or all configured git_pillar remotes. .. note:: This will *not* fast-forward the git_pillar cachedir on the master. All it does is perform a ``git fetch``. If this runner is executed with ``-l debug``, you may see a log message that says that the repo is up-to-date. Keep in mind that Salt automatically fetches git_pillar repos roughly every 60 seconds (or whatever :conf_master:`loop_interval` is set to). So, it is possible that the repo was fetched automatically in the time between when changes were pushed to the repo, and when this runner was executed. When in doubt, simply refresh pillar data using :py:func:`saltutil.refresh_pillar <salt.modules.saltutil.refresh_pillar>` and then use :py:func:`pillar.item <salt.modules.pillar.item>` to check if the pillar data has changed as expected. CLI Example: .. code-block:: bash # Update specific branch and repo salt-run git_pillar.update branch='branch' repo='https://foo.com/bar.git' # Update all repos salt-run git_pillar.update # Run with debug logging salt-run git_pillar.update -l debug ''' ret = {} for ext_pillar in __opts__.get('ext_pillar', []): pillar_type = next(iter(ext_pillar)) if pillar_type != 'git': continue pillar_conf = ext_pillar[pillar_type] pillar = salt.utils.gitfs.GitPillar( __opts__, pillar_conf, per_remote_overrides=salt.pillar.git_pillar.PER_REMOTE_OVERRIDES, per_remote_only=salt.pillar.git_pillar.PER_REMOTE_ONLY) for remote in pillar.remotes: # Skip this remote if it doesn't match the search criteria if branch is not None: if branch != remote.branch: continue if repo is not None: if repo != remote.url: continue try: result = remote.fetch() except Exception as exc: log.error( 'Exception \'%s\' caught while fetching git_pillar ' 'remote \'%s\'', exc, remote.id, exc_info_on_loglevel=logging.DEBUG) result = False finally: remote.clear_lock() ret[remote.id] = result if not ret: if branch is not None or repo is not None: raise SaltRunnerError( 'Specified git branch/repo not found in ext_pillar config') else: raise SaltRunnerError('No git_pillar remotes are configured') return ret
def gen_csr(minion_id, dns_name, organization_id, ou_name=None, key_len=2048, shatype='sha256', password=None): ''' CLI Example: .. code-block:: bash salt-run digicert.gen_csr <minion_id> <dns_name> ''' org_details = get_org_details(organization_id) if 'error' in org_details: raise SaltRunnerError( 'Problem getting organization details for organization_id={0} ({1})' .format(organization_id, org_details['error'])) if org_details['dict'].get('status', 'active') == 'inactive': raise SaltRunnerError( 'Organization with organization_id={0} is marked inactive'.format( organization_id)) tmpdir = tempfile.mkdtemp() os.chmod(tmpdir, 0o700) bank = 'digicert/domains' cache = salt.cache.Cache(__opts__, syspaths.CACHE_DIR) data = cache.fetch(bank, dns_name) if data is None: data = {} if 'private_key' not in data: data['private_key'] = gen_key(minion_id, dns_name, password, key_len=key_len) tmppriv = '{0}/priv'.format(tmpdir) tmpcsr = '{0}/csr'.format(tmpdir) with salt.utils.files.fopen(tmppriv, 'w') as if_: if_.write(salt.utils.stringutils.to_str(data['private_key'])) subject = '/C={0}/ST={1}/L={2}/O={3}'.format( org_details['dict']['country'], org_details['dict']['state'], org_details['dict']['city'], org_details['dict']['display_name']) if ou_name: subject = subject + '/OU={0}'.format(ou_name) subject = subject + '/CN={0}'.format(dns_name) cmd = "openssl req -new -{0} -key {1} -out {2} -subj '{3}'".format( shatype, tmppriv, tmpcsr, subject) output = __salt__['salt.cmd']('cmd.run', cmd) if 'problems making Certificate Request' in output: raise CommandExecutionError( 'There was a problem generating the CSR. Please ensure that you ' 'have a valid Organization established inside CertCentral') with salt.utils.files.fopen(tmpcsr, 'r') as of_: csr = salt.utils.stringutils.to_unicode(of_.read()) data['minion_id'] = minion_id data['csr'] = csr cache.store(bank, dns_name, data) return csr
def order_certificate(minion_id, common_name, organization_id, validity_years, cert_key_passphrase=None, signature_hash=None, key_len=2048, dns_names=None, organization_units=None, server_platform=None, custom_expiration_date=None, comments=None, disable_renewal_notifications=False, product_type_hint=None, renewal_of_order_id=None): ''' Order a certificate. Requires that an Organization has been created inside Digicert's CertCentral. See here for API documentation: https://www.digicert.com/services/v2/documentation/order/order-ssl-determinator CLI Example: .. code-block:: bash salt-run digicert.order_certificate my_minionid my.domain.com 10 \ 3 signature_hash=sha256 \ dns_names=['this.domain.com', 'that.domain.com'] \ organization_units='My Domain Org Unit' \ comments='Comment goes here for the approver' This runner can also be used to renew a certificate by passing `renewal_of_order_id`. Previous order details can be retrieved with digicertapi.list_orders. ''' if dns_names and isinstance(dns_names, six.string_types): dns_names = [dns_names] if dns_names and not isinstance(dns_names, collections.Sequence): raise SaltRunnerError( 'order_certificate needs a single dns_name, or an array of dns_names.' ) certificate = {'common_name': common_name} certificate['dns_names'] = dns_names if signature_hash: certificate['signature_hash'] = signature_hash else: certificate['signature_hash'] = __opts__.get('digicert', {}).get( 'shatype', 'sha256') body = {} if organization_units and isinstance(organization_units, six.string_types): organization_units = [organization_units] if organization_units and not isinstance(organization_units, collections.Sequence): raise SaltRunnerError('Organization_units is not a valid data type.') if organization_units: certificate['organization_units'] = organization_units if organization_units: # Currently the Digicert API requires organization units to be an array # but only pays attention to the first one. csr = gen_csr(minion_id, common_name, organization_id, ou_name=organization_units[0], shatype=certificate['signature_hash'], key_len=key_len, password=cert_key_passphrase) else: csr = gen_csr(minion_id, common_name, organization_id, shatype=certificate['signature_hash'], key_len=key_len, password=cert_key_passphrase) certificate['csr'] = csr if server_platform: certificate['server_platform']['id'] = server_platform body['organization'] = {'id': organization_id} if custom_expiration_date: body['custom_expiration_date'] = custom_expiration_date if validity_years: body['validity_years'] = validity_years if comments: body['comments'] = comments body['disable_renewal_notifications'] = disable_renewal_notifications if product_type_hint: body['product'] = {'type_hint': product_type_hint} if renewal_of_order_id: body['renewal_of_order_id'] = renewal_of_order_id body['certificate'] = certificate encoded_body = salt.utils.json.dumps(body) qdata = salt.utils.http.query('{0}/order/certificate/ssl'.format( _base_url()), method='POST', data=encoded_body, decode=True, decode_type='json', header_dict={ 'X-DC-DEVKEY': _api_key(), 'Content-Type': 'application/json', }, raise_error=False) if 'errors' not in qdata['dict']: bank = 'digicert/domains' cache = salt.cache.Cache(__opts__, syspaths.CACHE_DIR) data = cache.fetch(bank, common_name) if data is None: data = {} data.update({ 'minion_id': minion_id, 'order_id': qdata['dict']['requests'][0]['id'], 'csr': csr, }) cache.store(bank, common_name, data) _id_map(minion_id, common_name) return {'order': qdata['dict']}
def update(branch=None, repo=None): ''' .. versionadded:: 2014.1.0 .. versionchanged:: 2015.8.4 This runner function now supports the :ref:`new git_pillar configuration schema <git-pillar-2015-8-0-and-later>` introduced in 2015.8.0. Additionally, the branch and repo can now be omitted to update all git_pillar remotes. The return data has also changed. For releases 2015.8.3 and earlier, there is no value returned. Starting with 2015.8.4, the return data is a dictionary. If using the :ref:`old git_pillar configuration schema <git-pillar-pre-2015-8-0>`, then the dictionary values will be ``True`` if the update completed without error, and ``False`` if an error occurred. If using the :ref:`new git_pillar configuration schema <git-pillar-2015-8-0-and-later>`, the values will be ``True`` only if new commits were fetched, and ``False`` if there were errors or no new commits were fetched. Fetch one or all configured git_pillar remotes. .. note:: This will *not* fast-forward the git_pillar cachedir on the master. All it does is perform a ``git fetch``. If this runner is executed with ``-l debug``, you may see a log message that says that the repo is up-to-date. Keep in mind that Salt automatically fetches git_pillar repos roughly every 60 seconds (or whatever :conf_master:`loop_interval` is set to). So, it is possible that the repo was fetched automatically in the time between when changes were pushed to the repo, and when this runner was executed. When in doubt, simply refresh pillar data using :py:func:`saltutil.refresh_pillar <salt.modules.saltutil.refresh_pillar>` and then use :py:func:`pillar.item <salt.modules.pillar.item>` to check if the pillar data has changed as expected. CLI Example: .. code-block:: bash # Update specific branch and repo salt-run git_pillar.update branch='branch' repo='https://foo.com/bar.git' # Update all repos (2015.8.4 and later) salt-run git_pillar.update # Run with debug logging salt-run git_pillar.update -l debug ''' ret = {} for ext_pillar in __opts__.get('ext_pillar', []): pillar_type = next(iter(ext_pillar)) if pillar_type != 'git': continue pillar_conf = ext_pillar[pillar_type] if isinstance(pillar_conf, six.string_types): parts = pillar_conf.split() if len(parts) >= 2: desired_branch, desired_repo = parts[:2] # Skip this remote if it doesn't match the search criteria if branch is not None: if branch != desired_branch: continue if repo is not None: if repo != desired_repo: continue ret[pillar_conf] = salt.pillar.git_pillar._LegacyGitPillar( parts[0], parts[1], __opts__).update() else: pillar = salt.utils.gitfs.GitPillar(__opts__) pillar.init_remotes(pillar_conf, salt.pillar.git_pillar.PER_REMOTE_OVERRIDES, salt.pillar.git_pillar.PER_REMOTE_ONLY) for remote in pillar.remotes: # Skip this remote if it doesn't match the search criteria if branch is not None: if branch != remote.branch: continue if repo is not None: if repo != remote.url: continue try: result = remote.fetch() except Exception as exc: log.error( 'Exception \'{0}\' caught while fetching git_pillar ' 'remote \'{1}\''.format(exc, remote.id), exc_info_on_loglevel=logging.DEBUG) result = False finally: remote.clear_lock() ret[remote.id] = result if not ret: if branch is not None or repo is not None: raise SaltRunnerError( 'Specified git branch/repo not found in ext_pillar config') else: raise SaltRunnerError('No git_pillar remotes are configured') return ret
def update(branch=None, repo=None): ''' .. versionadded:: 2014.1.0 .. versionchanged:: 2015.8.4 This runner function now supports the :ref:`new git_pillar configuration schema <git-pillar-2015-8-0-and-later>` introduced in 2015.8.0. Additionally, the branch and repo can now be omitted to update all git_pillar remotes. The return data has also changed. For releases 2015.8.3 and earlier, there is no value returned. Starting with 2015.8.4, the return data is a dictionary. If using the :ref:`old git_pillar configuration schema <git-pillar-pre-2015-8-0>`, then the dictionary values will be ``True`` if the update completed without error, and ``False`` if an error occurred. If using the :ref:`new git_pillar configuration schema <git-pillar-2015-8-0-and-later>`, the values will be ``True`` only if new commits were fetched, and ``False`` if there were errors or no new commits were fetched. Update one or all configured git_pillar remotes. CLI Example: .. code-block:: bash # Update specific branch and repo salt-run git_pillar.update branch='branch' repo='https://foo.com/bar.git' # Update all repos (2015.8.4 and later) salt-run git_pillar.update # Run with debug logging salt-run git_pillar.update -l debug ''' ret = {} for ext_pillar in __opts__.get('ext_pillar', []): pillar_type = next(iter(ext_pillar)) if pillar_type != 'git': continue pillar_conf = ext_pillar[pillar_type] if isinstance(pillar_conf, six.string_types): parts = pillar_conf.split() if len(parts) >= 2: desired_branch, desired_repo = parts[:2] # Skip this remote if it doesn't match the search criteria if branch is not None: if branch != desired_branch: continue if repo is not None: if repo != desired_repo: continue ret[pillar_conf] = salt.pillar.git_pillar._LegacyGitPillar( parts[0], parts[1], __opts__).update() else: pillar = salt.utils.gitfs.GitPillar(__opts__) pillar.init_remotes(pillar_conf, salt.pillar.git_pillar.PER_REMOTE_OVERRIDES) for remote in pillar.remotes: # Skip this remote if it doesn't match the search criteria if branch is not None: if branch != remote.branch: continue if repo is not None: if repo != remote.url: continue try: result = remote.fetch() except Exception as exc: log.error( 'Exception \'{0}\' caught while fetching git_pillar ' 'remote \'{1}\''.format(exc, remote.id), exc_info_on_loglevel=logging.DEBUG ) result = False finally: remote.clear_lock() ret[remote.id] = result if not ret: if branch is not None or repo is not None: raise SaltRunnerError( 'Specified git branch/repo not found in ext_pillar config' ) else: raise SaltRunnerError('No git_pillar remotes are configured') return ret