如何使用saltstack设置一个随机密钥

时间:2018-02-11 08:50:36

标签: salt-stack

我安装了一个类似于(简化)的rails的配置:

production:
    secret_key_base: 800afb35d5086b2c60ebd35c01b2bd2b522c2492
    db_username: ...
    db_password: ...

因此从模板文件安装

{{ role }}:
    secret_key_base: {{ secret_key }}
    db_username: {{ db_user }}
    db_password: {{ db_pass }}

角色和db user / pass从支柱中拉出并安装在该文件中。 secret_key随机生成是有意义的,例如{{ salt['random.get_str'](length=80) }}。但我希望生成一次,而不是每次渲染模板。 (更改密钥会使cookie无效,而不是每次盐运行都要做。)

我发现的唯一解决方案是两阶段:我有一个template.in文件

{{ role }}:
    secret_key_base: ||secret_key_base||
    db_username: {{ db_user }}
    db_password: {{ db_pass }}

我在任何给定的小兵上进入我的模板文件:

/srv/salt/rails/secrets.yml:
  cmd.run:
    # Fill in the secret key base (used for cookies).  We can't use
    # jinja2 for this, since jinja would complain about the other
    # variables that it doesn't know how to replace.  We want our
    # output to be a jinja template.
    - name: |
        cat /srv/salt/rails/secrets.yml.in | \
          sed -e 's/||secret_key_base||/{{ salt['random.get_str'](length=80) }}/;' | \
          cat > /srv/salt/rails/secrets.yml
        chmod 400 /srv/salt/rails/secrets.yml
    - creates: /srv/salt/rails/secrets.yml
    - runas: root

/var/railroad/{{host_role}}/shared/config/secrets.yml:
  file.managed:
    - source: salt://rails/secrets.yml
    - mode: 400
    - user: railroad-{{host_role}}
    - group: railroad-{{host_role}}
    - template: jinja
    - defaults:
        role: host_role
        db_username: m_u
        db_password: m_p

这有效,但缺点是secrets.yml.in的更改不会传播到secrets.yml。 (假设我们在秘密文件中添加了另一个密钥。)它也比必要时感觉更笨拙。

有更好的方法吗?

更好的方法

正如评论中所指出的,更好的方法是手工生成秘密(毕竟,它只在主机设置中完成)并将其存储在支柱中,我们无论如何都要说几件事关于每个主人。

以下是工作代码的最终结果,对于那些可能希望看到更复杂的内容的人来说,这些代码是未经简化的。很多复杂性是我的host_credentials支柱数据,它试图描述我们需要了解的每个主机的所有信息。

{% set fqdn = grains.get('fqdn', 'unknown-host-fqdn') %}
{% set host_role = pillar['host_credentials']
                         [grains.get('fqdn')]
                         ['role'] %}
{% set examplecom_web_app = pillar['host_credentials']
                                  [grains.get('fqdn')]
                                  ['examplecom-web-app'] %}
{% set mysql_server_host = examplecom_web_app.mysql.host %}
{% set mysql_server_database = examplecom_web_app.mysql.database %}
{% set mysql_server_role = examplecom_web_app.mysql.role %}
{% set mysql_server_spec = pillar['host_credentials']
                                 [mysql_server_host]
                                 ['mysql'] %}
{% set mongodb_server_host = examplecom_web_app.mongodb.host %}
{% set mongodb_server_spec = pillar['host_credentials']
                                   [mongodb_server_host]
                                   ['mongodb'] %}
/var/examplecom/railroad/{{host_role}}/shared/config/secrets.yml:
  file.managed:
    - source: salt://rails/secrets.yml
    - mode: 400
    - user: railroad-{{host_role}}
    - group: railroad-{{host_role}}
    - template: jinja
    - defaults:
        role: {{ host_role }}
        secret_key_base: {{ examplecom_web_app.secret_key_base }}
        mysql_hostname: {{ mysql_server_host }}
        mysql_username: {{ mysql_server_spec[mysql_server_database]
                                            [mysql_server_role]
                                            ['username'] }}
        mysql_password: {{ mysql_server_spec[mysql_server_database]
                                            [mysql_server_role]
                                            ['password'] }}
        mongodb_hostname: {{ mongodb_server_host }}
        mongodb_username: {{ mongodb_server_spec.username }}
        mongodb_password: {{ mongodb_server_spec.password }}

顺便说一句,我很高兴地发现jinja2是白空间不可知的,这对于这种查找的可读性非常有帮助。

2 个答案:

答案 0 :(得分:2)

我建议将秘密放入支柱并在主设备上生成一次(手动)值。这样您就可以避免在SLS文件中执行有状态的动态魔法。

jma更新了他的问题以包含一个示例解决方案。

答案 1 :(得分:0)

我是否理解正确:
  - 这是盐无主的运行?   - 在无主节点上生成一些模板文件(生成一些静态部分)
  - 您将file.managed状态应用于以前生成的文件吗?

假设我的理解:

首先,如果你设置了正确的watch/require statements传播到其他州,但在你的情况下,由于你已经使用了{{1},这将更难实现用于模板解析(必须添加cmd.run参数to express that there is some potential state changes underlying

说明:
  - 你看到了file.blockreplace吗?您似乎可以使用它来替换第一个stateful并获取文件更改检测"免费"
  - 对于一次性密码生成,只需使用grains.get_or_set_hash

就可以做到这一点

由于生成的密码没有针对给定的minion(您的情况下是无主节点)而更改,cmd.run不会报告任何更改,除非您向模板添加更改

话虽如此,我认为我们可以更进一步,你的状态实际上可以像这样简单(模板更改将始终传播,密钥将生成一次):

file.blockreplace