Page MenuHomeDevCentral

D2638.id6666.diff
No OneTemporary

D2638.id6666.diff

diff --git a/_modules/credentials.py b/_modules/credentials.py
new file mode 100644
--- /dev/null
+++ b/_modules/credentials.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+
+# -------------------------------------------------------------
+# Salt — Credentials
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# Description: Credentials-related execution module methods
+# License: BSD-2-Clause
+# -------------------------------------------------------------
+
+
+from salt.utils.files import fopen
+
+
+# -------------------------------------------------------------
+# HOF utilities
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def _filter_discard_empty_string_values(haystack):
+ if type(haystack) is dict:
+ return {k: v for k, v in haystack.items() if v != ""}
+
+ if type(haystack) is list:
+ return [v for v in haystack if v != ""]
+
+ raise ValueError("Argument isn't a list or a dict: " + str(type(haystack)))
+
+
+def _join_document_fragments(fragments):
+ filtered = _filter_discard_empty_string_values(fragments)
+ return "\n\n".join(filtered)
+
+
+# -------------------------------------------------------------
+# Build Vault policies
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+class VaultSaltRolePolicy:
+ def __init__(self, role):
+ self.role = role
+
+ def build_policy(self):
+ return _join_document_fragments(
+ [
+ self.build_read_secrets_policy(),
+ self.import_extra_policies(),
+ ]
+ )
+
+ #
+ # Secrets from pillar entry vault_secrets_by_role
+ #
+
+ def build_read_secrets_policy(self):
+ vault_paths = __pillar__["vault_secrets_by_role"].get(self.role, [])
+
+ return _join_document_fragments(
+ [self.get_read_rule(vault_path) for vault_path in vault_paths]
+ )
+
+ @staticmethod
+ def get_read_rule(vault_path):
+ return f"""
+path \"{vault_path}\" {{
+ capabilities = [ \"read\" ]
+}}
+"""
+
+ #
+ # Import policies from pillar entry vault_extra_policies_by_role
+ #
+
+ def import_extra_policies(self):
+ extra_policies = __pillar__["vault_extra_policies_by_role"].get(self.role, [])
+ return _join_document_fragments(
+ [self.import_policy(policy) for policy in extra_policies]
+ )
+
+ @staticmethod
+ def import_policy(policy):
+ policy_file = f"{__pillar__['vault_policies_source']}/{policy}.hcl"
+ return f"# Import policy: {policy_file}"
+ # with fopen(policy_file) as fd:
+ # return fd.read()
+
+
+def _compile_roles_policies():
+ return {
+ role: VaultSaltRolePolicy(role).build_policy() for role in _get_relevant_roles()
+ }
+
+
+def _get_relevant_roles():
+ return {
+ role
+ for pillar_entry in [
+ "vault_extra_policies_by_role",
+ "vault_secrets_by_role",
+ ]
+ for role in __pillar__[pillar_entry].keys()
+ }
+
+
+def _build_node_policy(node, roles_policies):
+ rules = [
+ roles_policies[role]
+ for role in __salt__["node.get"]("roles", node)
+ if role in roles_policies
+ ]
+ return _join_document_fragments(rules)
+
+
+def build_policies_by_node():
+ roles_policies = _compile_roles_policies()
+
+ policies = {
+ node: _build_node_policy(node, roles_policies)
+ for node in __pillar__["nodes"].keys()
+ }
+
+ return _filter_discard_empty_string_values(policies)
diff --git a/_states/credentials.py b/_states/credentials.py
new file mode 100644
--- /dev/null
+++ b/_states/credentials.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+# -------------------------------------------------------------
+# Salt — Credentials state
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# Description: Allow to declare credentials-related states
+# License: BSD-2-Clause
+# -------------------------------------------------------------
+
+
+from salt.states import vault
+from salt.utils.files import fopen
+
+
+def vault_policy_present(name, policy_file):
+ """
+ Ensure a Vault policy with the given name is present.
+
+ name
+ The name of the policy
+ policy_file
+ Path to a file on the minion containing rules,
+ formatted in HCL.
+
+ .. code-block:: yaml
+
+ demo_policy:
+ vault.policy_present:
+ - name: foo/bar
+ - policy_file: /opt/vault-policies/demo.hcl
+
+ """
+ with fopen(policy_file) as fd:
+ rules = fd.read()
+
+ return vault.policy_present(name, rules)
diff --git a/pillar/credentials/vault.sls b/pillar/credentials/vault.sls
new file mode 100644
--- /dev/null
+++ b/pillar/credentials/vault.sls
@@ -0,0 +1,113 @@
+# -------------------------------------------------------------
+# Salt configuration for Nasqueron servers
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: Trivial work, not eligible to copyright
+# -------------------------------------------------------------
+
+vault_policies_path: /srv/policies/vault
+vault_policies_source: salt://roles/vault/policies/files
+
+# -------------------------------------------------------------
+# Vault policies to deploy as-is, ie without templating.
+#
+# Entries of vault_policies must match a .hcl file in
+# roles/vault/policies/files folder.
+#
+# If you need a template, create a new pillar entry instead
+# and add the parsing logic either:
+# - directly to roles/vault/policies/
+#
+# - through _modules/credentials.py for policies to apply
+# to Salt nodes, like e.g. vault_secrets_by_role
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+vault_policies:
+ - salt_primary
+
+# -------------------------------------------------------------
+# Vault policies for Salt
+#
+# Declare the extra policies each nodes need.
+#
+# In adition of those extra policies, the vault_secrets_by_role
+# will be parsed for the keys.
+#
+# IMPORTANT: as grains['roles'] can be modified by the node,
+# roles are extracted directly from the pillar.
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+vault_extra_policies_by_role:
+ salt-primary:
+ - salt_primary
+
+# -------------------------------------------------------------
+# Vault secrets by role
+#
+# Paths of the keys the specified role needs access to.
+#
+# Avoid * notation as this namespace is shared between Vault
+# and the applications. As such, only secrets the Salt nodes
+# needs in a state they need to deploy should be listed here.
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+vault_secrets_by_role:
+
+ opensearch:
+ - ops/secrets/nasqueron.opensearch.infra-logs.internal_users.admin
+ - ops/secrets/nasqueron.opensearch.infra-logs.internal_users.dashboards
+
+ paas-docker:
+
+ #
+ # Personal data or personally identifiable information (PII)
+ # related to Nasqueron Operations SIG members.
+ #
+
+ - ops/privacy/ops-cidr
+
+ #
+ # Credentials used by Nasqueron services
+ # Format: ops/secrets/nasqueron.<service>.<type>
+ #
+
+ - ops/secrets/nasqueron.acquisitariat.mysql
+
+ - ops/secrets/nasqueron.auth-grove.mysql
+
+ - ops/secrets/nasqueron.cachet.app_key
+ - ops/secrets/nasqueron.cachet.mysql
+
+ - ops/secrets/nasqueron.etherpad.api
+
+ - ops/secrets/nasqueron.notifications.broker
+ - ops/secrets/nasqueron.notifications.mailgun
+ - ops/secrets/nasqueron.notifications.sentry
+
+ - ops/secrets/nasqueron.pixelfed.app_key
+ - ops/secrets/nasqueron.pixelfed.mailgun
+ - ops/secrets/nasqueron.pixelfed.mysql
+
+ - ops/secrets/nasqueron.sentry.app_key
+ - ops/secrets/nasqueron.sentry.postgresql
+
+ #
+ # Credentials used by Nasqueron members private services
+ # Format: <username>.<service>.<type>
+ #
+
+ - ops/secrets/dereckson.phabricator.mysql
+
+ #
+ # Credentials used by projects hosted by Nasqueron
+ # Format: <project name>.<service>.<type>
+ #
+
+ - ops/secrets/espacewin.bugzilla.mysql
+
+ - ops/secrets/wolfplex.phabricator.mailgun
+ - ops/secrets/wolfplex.phabricator.mysql
+
+ - ops/secrets/zed.phabricator.mysql
+ - ops/secrets/zed.phabricator.sendgrid
diff --git a/pillar/nodes/nodes.sls b/pillar/nodes/nodes.sls
--- a/pillar/nodes/nodes.sls
+++ b/pillar/nodes/nodes.sls
@@ -44,6 +44,9 @@
hostname: complector.nasqueron.org
roles:
- vault
+ - salt-primary
+
+ # Deprecated, use salt-primary, a more inclusive terminology
- saltmaster
zfs:
pool: zroot
diff --git a/pillar/top.sls b/pillar/top.sls
--- a/pillar/top.sls
+++ b/pillar/top.sls
@@ -22,6 +22,9 @@
- opensearch.software
- opensearch.clusters
+ complector:
+ - credentials.vault
+
docker-001:
- credentials.zr
- paas.docker
diff --git a/roles/vault/init.sls b/roles/vault/init.sls
--- a/roles/vault/init.sls
+++ b/roles/vault/init.sls
@@ -7,3 +7,6 @@
include:
- .vault
+
+ # Depends of Vault installed
+ - .policies
diff --git a/roles/vault/policies/files/salt_primary.hcl b/roles/vault/policies/files/salt_primary.hcl
new file mode 100644
--- /dev/null
+++ b/roles/vault/policies/files/salt_primary.hcl
@@ -0,0 +1,26 @@
+# -------------------------------------------------------------
+# Vault configuration - Policy for salt primary server
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: Trivial work, not eligible to copyright
+# Source file: roles/vault/vault/files/salt_primary.hcl
+# -------------------------------------------------------------
+#
+# <auto-generated>
+# This file is managed by our rOPS SaltStack repository.
+#
+# Changes to this file may cause incorrect behavior
+# and will be lost if the state is redeployed.
+# </auto-generated>
+
+# -------------------------------------------------------------
+# Policies management
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+path "sys/policies/acl" {
+ capabilities = ["list"]
+}
+
+path "sys/policies/acl/*" {
+ capabilities = ["create", "read", "update", "delete", "list", "sudo"]
+}
diff --git a/roles/vault/policies/init.sls b/roles/vault/policies/init.sls
new file mode 100644
--- /dev/null
+++ b/roles/vault/policies/init.sls
@@ -0,0 +1,52 @@
+# -------------------------------------------------------------
+# Salt — Vault
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: Trivial work, not eligible to copyright
+# -------------------------------------------------------------
+
+{% set policies_path = pillar['vault_policies_path'] %}
+
+# -------------------------------------------------------------
+# Policies storage folder
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+{{ policies_path }}:
+ file.directory:
+ - makedirs: True
+
+# -------------------------------------------------------------
+# Policies from vault_policies pillar entry
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+{% for policy in pillar['vault_policies'] %}
+{% set policy_path = policies_path + "/" + policy + ".hcl" %}
+
+{{ policy_path }}:
+ file.managed:
+ - source: salt://roles/vault/policies/files/{{ policy }}.hcl
+
+vault_policy_{{ policy }}:
+ credentials.vault_policy_present:
+ - name: {{ policy }}
+ - policy_file: {{ policy_path }}
+ - onchanges:
+ - file: {{ policy_path }}
+
+{% endfor %}
+
+# -------------------------------------------------------------
+# Policies per nodes intended to be used through Salt
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+{% for node, rules in salt['credentials.build_policies_by_node']().items() %}
+salt_node_{{ node }}:
+ vault.policy_present:
+ - rules: |
+ #
+ # <auto-generated>
+ # This policy is managed by our rOPS SaltStack repository.
+ # </auto-generated>
+ #
+ {{ rules | indent(8) }}
+{% endfor %}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 16, 16:40 (22 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2247791
Default Alt Text
D2638.id6666.diff (12 KB)

Event Timeline