Wolfgang Kulhanek
2019-01-31 3a536f507668cc04221a5917776d316d1a5edb2b
Updated Let's Encrypt to use the fullchain.cer instead of server.cer to remove errors on 'oc login' and other scenarios.
1 files added
6 files modified
440 ■■■■■ changed files
ansible/configs/ocp-workshop/env_vars.yml 4 ●●●● patch | view | raw | blame | history
ansible/configs/ocp-workshop/files/hosts_template.3.11.69.j2 375 ●●●●● patch | view | raw | blame | history
ansible/configs/ocp-workshop/pre_software.yml 1 ●●●● patch | view | raw | blame | history
ansible/configs/quay-enterprise/software.yml 3 ●●●● patch | view | raw | blame | history
ansible/roles/host-lets-encrypt-certs/README.md 27 ●●●●● patch | view | raw | blame | history
ansible/roles/host-lets-encrypt-certs/defaults/main.yml 9 ●●●●● patch | view | raw | blame | history
ansible/roles/host-lets-encrypt-certs/tasks/main.yml 21 ●●●●● patch | view | raw | blame | history
ansible/configs/ocp-workshop/env_vars.yml
@@ -169,12 +169,12 @@
openshift_master_overwrite_named_certificates: true
lets_encrypt_openshift_master_named_certificates:
  - certfile: "/root/.acme.sh/{{ master_lb_dns }}/{{ master_lb_dns }}.cer"
  - certfile: "/root/.acme.sh/{{ master_lb_dns }}/fullchain.cer"
    keyfile: "/root/.acme.sh/{{ master_lb_dns }}/{{ master_lb_dns }}.key"
    cafile: "/root/.acme.sh/{{ master_lb_dns }}/ca.cer"
lets_encrypt_openshift_hosted_router_certificate:
  certfile: "/root/.acme.sh/{{ master_lb_dns }}/{{ master_lb_dns }}.cer"
  certfile: "/root/.acme.sh/{{ master_lb_dns }}/fullchain.cer"
  keyfile: "/root/.acme.sh/{{ master_lb_dns }}/{{ master_lb_dns }}.key"
  cafile: "/root/.acme.sh/{{ master_lb_dns }}/ca.cer"
ansible/configs/ocp-workshop/files/hosts_template.3.11.69.j2
New file
@@ -0,0 +1,375 @@
#
# /etc/ansible/hosts file for OpenShift Container Platform 3.11.69
#
[OSEv3:vars]
###########################################################################
### Ansible Vars
###########################################################################
timeout=60
ansible_user={{ansible_user}}
ansible_become=yes
log_path=/root
###########################################################################
### OpenShift Basic Vars
###########################################################################
openshift_deployment_type=openshift-enterprise
openshift_disable_check="disk_availability,memory_availability,docker_image_availability"
openshift_image_tag=v{{ osrelease }}
openshift_pkg_version=-{{ osrelease }}
openshift_release={{ osrelease }}
{% if container_runtime == "cri-o" %}
openshift_use_crio=True
openshift_use_crio_only=False
openshift_crio_enable_docker_gc=True
{% endif %}
# openshift_node_groups=[{'name': 'node-config-master', 'labels': ['node-role.kubernetes.io/master=true','runtime={{container_runtime}}']}, {'name': 'node-config-infra', 'labels': ['node-role.kubernetes.io/infra=true','runtime={{container_runtime}}']}, {'name': 'node-config-glusterfs', 'labels': ['runtime={{container_runtime}}']}, {'name': 'node-config-compute', 'labels': ['node-role.kubernetes.io/compute=true','runtime={{container_runtime}}'], 'edits': [{ 'key': 'kubeletArguments.pods-per-core','value': ['20']}, { 'key': 'image-gc-high-threshold', 'value': ['85']}, { 'key': 'image-gc-low-threshold', 'value': ['75']}]}]
# Configure logrotate scripts
# See: https://github.com/nickhammond/ansible-logrotate
logrotate_scripts=[{"name": "syslog", "path": "/var/log/cron\n/var/log/maillog\n/var/log/messages\n/var/log/secure\n/var/log/spooler\n", "options": ["daily", "rotate 7","size 500M", "compress", "sharedscripts", "missingok"], "scripts": {"postrotate": "/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true"}}]
# Deploy Operator Lifecycle Management Tech Preview
openshift_enable_olm=true
##########################################################################
### OpenShift Registries Locations
###########################################################################
oreg_url=registry.redhat.io/openshift3/ose-${component}:${version}
oreg_auth_user={{ redhat_registry_user }}
oreg_auth_password={{ redhat_registry_password }}
# For Operator Framework Images
openshift_additional_registry_credentials=[{'host':'registry.connect.redhat.com','user':'{{ redhat_registry_user}}','password':'{{ redhat_registry_password }}','test_image':'mongodb/enterprise-operator:0.3.2'}]
openshift_examples_modify_imagestreams=true
{% if install_glusterfs|bool %}
###########################################################################
### OpenShift Container Storage
###########################################################################
openshift_master_dynamic_provisioning_enabled=True
# CNS storage cluster
# From https://github.com/red-hat-storage/openshift-cic
openshift_storage_glusterfs_namespace=openshift-storage
openshift_storage_glusterfs_storageclass=true
openshift_storage_glusterfs_storageclass_default=true
openshift_storage_glusterfs_block_deploy=true
openshift_storage_glusterfs_block_host_vol_create=true
openshift_storage_glusterfs_block_host_vol_size=200
openshift_storage_glusterfs_block_storageclass=true
openshift_storage_glusterfs_block_storageclass_default=false
# Container image to use for glusterfs pods
openshift_storage_glusterfs_image="registry.access.redhat.com/rhgs3/rhgs-server-rhel7:{{ glusterfs_image_tag }}"
# Container image to use for glusterblock-provisioner pod
openshift_storage_glusterfs_block_image="registry.access.redhat.com/rhgs3/rhgs-gluster-block-prov-rhel7:{{ glusterfs_image_tag }}"
# Container image to use for heketi pods
openshift_storage_glusterfs_heketi_image="registry.access.redhat.com/rhgs3/rhgs-volmanager-rhel7:{{ glusterfs_image_tag }}"
{% endif %}
{% if install_nfs|bool %}
# Set this line to enable NFS
openshift_enable_unsupported_configurations=True
{% endif %}
###########################################################################
### OpenShift Cockpit Vars
###########################################################################
# Enable cockpit
osm_use_cockpit=true
osm_cockpit_plugins=['cockpit-kubernetes']
###########################################################################
### OpenShift Master Vars
###########################################################################
openshift_master_api_port={{master_api_port}}
openshift_master_console_port={{master_api_port}}
openshift_master_cluster_method=native
openshift_master_cluster_hostname={{master_lb_private_dns}}
openshift_master_cluster_public_hostname={{master_lb_dns}}
openshift_master_default_subdomain={{cloudapps_suffix}}
openshift_master_overwrite_named_certificates={{openshift_master_overwrite_named_certificates}}
{% if install_lets_encrypt_certificates|bool %}
openshift_master_named_certificates={{lets_encrypt_openshift_master_named_certificates|to_json}}
{% endif %}
openshift_set_hostname=True
openshift_clock_enabled=True
###########################################################################
### OpenShift Network Vars
###########################################################################
osm_cluster_network_cidr=10.1.0.0/16
openshift_portal_net=172.30.0.0/16
# os_sdn_network_plugin_name='redhat/openshift-ovs-networkpolicy'
{{multi_tenant_setting}}
###########################################################################
### OpenShift Authentication Vars
###########################################################################
{% if install_idm == "ldap" or 'ldap' in install_idms|d([]) %}
{{openshift_master_ldap_ca_file}}
{% endif %}
{% if install_idm == "htpasswd" or 'htpasswd' in install_idms|d([]) %}
openshift_master_htpasswd_file=/root/htpasswd.openshift
{% endif %}
openshift_master_identity_providers={{identity_providers|to_json}}
{% if admission_plugin_config is defined %}
###########################################################################
### OpenShift admission plugin config
###########################################################################
openshift_master_admission_plugin_config={{admission_plugin_config|to_json}}
{% endif %}
###########################################################################
### OpenShift Metrics and Logging Vars
###########################################################################
####################
# Prometheus Metrics
####################
openshift_cluster_monitoring_operator_install=True
openshift_cluster_monitoring_operator_node_selector={"node-role.kubernetes.io/infra":"true"}
{% if install_glusterfs|bool %}
openshift_cluster_monitoring_operator_prometheus_storage_capacity=20Gi
openshift_cluster_monitoring_operator_alertmanager_storage_capacity=2Gi
openshift_cluster_monitoring_operator_prometheus_storage_enabled=True
openshift_cluster_monitoring_operator_alertmanager_storage_enabled=True
# The next two will be enabled in 3.11.z
# openshift_cluster_monitoring_operator_prometheus_storage_class_name='glusterfs-storage-block'
# openshift_cluster_monitoring_operator_alertmanager_storage_class_name='glusterfs-storage-block'
{% endif %}
#################
# Cluster metrics
#################
openshift_metrics_install_metrics={{install_metrics}}
{% if install_nfs|bool and not install_glusterfs|bool %}
openshift_metrics_storage_kind=nfs
openshift_metrics_storage_access_modes=['ReadWriteOnce']
openshift_metrics_storage_nfs_directory=/srv/nfs
openshift_metrics_storage_nfs_options='*(rw,root_squash)'
openshift_metrics_storage_volume_name=metrics
openshift_metrics_storage_labels={'storage': 'metrics'}
openshift_metrics_cassandra_pvc_storage_class_name=''
{% endif %}
{% if install_glusterfs|bool %}
openshift_metrics_cassandra_storage_type=dynamic
openshift_metrics_cassandra_pvc_storage_class_name='glusterfs-storage-block'
{% endif %}
openshift_metrics_cassandra_pvc_size=10Gi
openshift_metrics_hawkular_nodeselector={"node-role.kubernetes.io/infra": "true"}
openshift_metrics_cassandra_nodeselector={"node-role.kubernetes.io/infra": "true"}
openshift_metrics_heapster_nodeselector={"node-role.kubernetes.io/infra": "true"}
# Store Metrics for 2 days
openshift_metrics_duration=2
#################
# Cluster logging
#################
openshift_logging_install_logging={{ install_logging }}
openshift_logging_install_eventrouter={{ install_logging }}
{% if install_nfs|bool and not install_glusterfs|bool %}
openshift_logging_storage_kind=nfs
openshift_logging_storage_access_modes=['ReadWriteOnce']
openshift_logging_storage_nfs_directory=/srv/nfs
openshift_logging_storage_nfs_options='*(rw,root_squash)'
openshift_logging_storage_volume_name=logging
openshift_logging_storage_volume_size=10Gi
openshift_logging_storage_labels={'storage': 'logging'}
openshift_logging_es_pvc_storage_class_name=''
{% endif %}
{% if install_glusterfs|bool %}
openshift_logging_es_pvc_dynamic=true
openshift_logging_es_pvc_size=20Gi
openshift_logging_es_pvc_storage_class_name='glusterfs-storage-block'
{% endif %}
openshift_logging_es_cluster_size=1
openshift_logging_curator_default_days=2
openshift_logging_kibana_nodeselector={"node-role.kubernetes.io/infra": "true"}
openshift_logging_curator_nodeselector={"node-role.kubernetes.io/infra": "true"}
openshift_logging_es_nodeselector={"node-role.kubernetes.io/infra": "true"}
openshift_logging_eventrouter_nodeselector={"node-role.kubernetes.io/infra": "true"}
###########################################################################
### OpenShift Router and Registry Vars
###########################################################################
openshift_hosted_router_replicas={{infranode_instance_count}}
{% if install_lets_encrypt_certificates|bool %}
openshift_hosted_router_certificate={{lets_encrypt_openshift_hosted_router_certificate|to_json}}
{% endif %}
{% if s3user_access_key is defined %}
# Registry AWS S3
# S3 bucket must already exist.
openshift_hosted_registry_storage_kind=object
openshift_hosted_registry_storage_provider=s3
openshift_hosted_registry_storage_s3_accesskey={{ s3user_access_key }}
openshift_hosted_registry_storage_s3_secretkey={{ s3user_secret_access_key }}
openshift_hosted_registry_storage_s3_bucket={{ project_tag }}
openshift_hosted_registry_storage_s3_region={{ aws_region_final|d(aws_region) }}
openshift_hosted_registry_storage_s3_chunksize=26214400
openshift_hosted_registry_storage_s3_rootdirectory=/registry
{% endif %}
openshift_hosted_registry_replicas=1
openshift_hosted_registry_pullthrough=true
openshift_hosted_registry_acceptschema2=true
openshift_hosted_registry_enforcequota=true
###########################################################################
### OpenShift Service Catalog Vars
###########################################################################
openshift_enable_service_catalog=true
template_service_broker_install=true
openshift_template_service_broker_namespaces=['openshift']
ansible_service_broker_install=true
ansible_service_broker_local_registry_whitelist=['.*-apb$']
###########################################################################
### OpenShift Hosts
###########################################################################
[OSEv3:children]
masters
etcd
nodes
{% if install_nfs|bool %}
nfs
{% endif %}
{% if install_glusterfs|bool %}
glusterfs
{% endif %}
{% if groups['newnodes']|d([])|length > 0 %}
new_nodes
{% endif %}
[masters]
{% for host in groups['masters']|sort %}
{{ hostvars[host].internaldns }}
{% endfor %}
[etcd]
{% for host in groups['masters']|sort %}
{{ hostvars[host].internaldns }}
{% endfor %}
[nodes]
## These are the masters
{% for host in groups['masters']|sort %}
{% if container_runtime == "cri-o" %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-master-crio'
{% else %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-master'
{% endif %}
{% endfor %}
## These are infranodes
{% for host in groups['infranodes']|sort %}
{% if container_runtime == "cri-o" %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-infra-crio'
{% else %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-infra'
{% endif %}
{% endfor %}
## These are regular nodes
{% for host in groups['nodes']|sort
  if host not in groups['newnodes']|d([])
  and host not in groups['glusterfs']|d([])
  %}
{% if container_runtime == "cri-o" %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-compute-crio'
{% else %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-compute'
{% endif %}
{% endfor %}
{% if groups['glusterfs']|d([])|length > 0 %}
## These are glusterfs nodes
{% for host in groups['glusterfs']|sort %}
{% if container_runtime == "cri-o" %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-compute-crio'
{% else %}
{{ hostvars[host].internaldns }} openshift_node_group_name='node-config-compute'
{% endif %}
{% endfor %}
{% endif %}
{% if groups['newnodes']|d([])|length > 0 %}
# scaleup performed, leave an empty group, see:
# https://docs.openshift.com/container-platform/3.7/install_config/adding_hosts_to_existing_cluster.html
[new_nodes]
{% for host in groups['newnodes']|sort %}
{% if container_runtime == "cri-o" %}
{{ hostvars[host].internaldns }} ansible_user={{remote_user}} ansible_ssh_private_key_file=~/.ssh/{{key_name}}.pem openshift_node_group_name='node-config-compute-crio'
{% else %}
{{ hostvars[host].internaldns }} ansible_user={{remote_user}} ansible_ssh_private_key_file=~/.ssh/{{key_name}}.pem openshift_node_group_name='node-config-compute'
{% endif %}
{% endfor %}
{% endif %}
{% if install_nfs|bool %}
[nfs]
{% for host in [groups['support']|sort|first] %}
{{ hostvars[host].internaldns }}
{% endfor %}
{% endif %}
{% if install_glusterfs|bool %}
{% set query = "[?name=='support']|[0].volumes[?purpose=='glusterfs'].device_name" %}
[glusterfs]
{% for host in groups['glusterfs']|sort %}
{% if  loop.index % 3 == 1 %}
{%   set glusterfs_zone = 1 %}
{% elif  loop.index % 3 == 2 %}
{%   set glusterfs_zone = 2 %}
{% elif  loop.index % 3 == 0 %}
{%   set glusterfs_zone = 3 %}
{% endif %}
{% if cloud_provider == 'ec2' %}
{{ hostvars[host].internaldns }} glusterfs_zone={{ glusterfs_zone }} glusterfs_devices='{{instances|json_query(query)|to_json}}'
{% elif cloud_provider == 'azure' %}
{{ hostvars[host].internaldns }} glusterfs_zone={{ glusterfs_zone }} glusterfs_devices='{{ [ hostvars[host].glusterfs_device_name ] |to_json}}'
{% endif %}
{% endfor %}
{% endif %}
ansible/configs/ocp-workshop/pre_software.yml
@@ -82,6 +82,7 @@
    - acme_cache_key_file: "{{output_dir}}/{{guid}}.key"
    - acme_cache_archive_file: "{{output_dir}}/{{guid}}_acme.tgz"
    - acme_cache_ca_file: "{{output_dir}}/{{guid}}_ca.cert"
    - acme_cache_fullchain_file: "{{output_dir}}/{{guid}}_fullchain.cer"
    - acme_renew_automatically: True
    - acme_force_issue: False
    when: install_lets_encrypt_certificates | d(False) | bool
ansible/configs/quay-enterprise/software.yml
@@ -62,13 +62,14 @@
      - acme_cache_cert_file: "{{output_dir}}/{{guid}}.cert"
      - acme_cache_key_file: "{{output_dir}}/{{guid}}.key"
      - acme_cache_archive_file: "{{output_dir}}/{{guid}}_acme.tgz"
      - acme_cache_fullchain_file: "{{output_dir}}/{{guid}}_fullchain.cer"
      - acme_production: "{{ qe_quay_ssl_lets_encrypt_production|d(False)|bool }}"
      - acme_renew_automatically: "{{ qe_quay_ssl_lets_encrypt_renew_automatically|d(False)|bool }}"
      - acme_force_issue: "{{ qe_quay_ssl_lets_encrypt_force_renew|d(False)|bool }}"
    - name: Set Cert/Key file locations to cached locations
      set_fact:
        qe_quay_ssl_key_file: "{{output_dir}}/{{guid}}.key"
        qe_quay_ssl_cert_file: "{{output_dir}}/{{guid}}.cert"
        qe_quay_ssl_cert_file: "{{output_dir}}/{{guid}}_fullchain.cer"
- name: Set up Node Software (Docker)
  hosts:
ansible/roles/host-lets-encrypt-certs/README.md
@@ -27,7 +27,8 @@
|*acme_cache_cert_file*|Yes| "/tmp/ssl.cert"| Local Cache File for Certificate
|*acme_cache_key_file*|Yes| "/tmp/ssl.key"|Local Cache File for Key
|*acme_cache_ca_file*|Yes| "/tmp/ssl_ca.cer"|Local Cache File for CA Certificate
|*acme_archive_file*|Yes| "/tmp/acme.tar.gz"| Local (to the host ansible is running on) cache of certificates. Prevents re-requesting certificates for later runs of the playbook when the domains haven't changed. acme.tar.gz will contain the entire .acme.sh directory so that it can be restored for future runs on new machines with the same domain names.
|*acme_cache_fullchain_file*|Yes| "/tmp/fullchain.cer"|Local Cache File for the Fullchain Certificate
|*acme_cache_archive_file*|Yes| "/tmp/acme.tar.gz"| Local (to the host ansible is running on) cache of certificates. Prevents re-requesting certificates for later runs of the playbook when the domains haven't changed. acme.tar.gz will contain the entire .acme.sh directory so that it can be restored for future runs on new machines with the same domain names.
|*acme_production*|Yes|False|Use the Production Let's Encrypt Server. Leave to False for testing runs to prevent issues with the Let's Encrypt rate limits
|*acme_renew_automatically*|Yes|False|Install a cron job to automatically renew Certificates. Checks once a day.
|*acme_force_issue*|Yes|False|Force the creation of new certificates even if there are certificates already on the host or certificates in the local cache
@@ -55,9 +56,11 @@
    - acme_domain: "master.example.opentlc.com"
    - acme_production: False
    - acme_remote_dir: "/root"
    - acme_local_cache_cert_file: "/tmp/server.cert"
    - acme_local_cache_key_file: "/tmp/server.key"
    - acme_local_cache_ca_file: "/tmp/server_ca.cer"
    - acme_cache_cert_file: "/tmp/server.cert"
    - acme_cache_key_file: "/tmp/server.key"
    - acme_cache_ca_file: "/tmp/server_ca.cer"
    - acme_cache_fullchain_file: "/tmp/fullchain.cer"
    - acme_cache_archive_file: "/tmp/acme.tar.gz"
    - acme_renew_automatically: False
    - acme_force_issue: False
@@ -74,9 +77,11 @@
    - acme_aws_secret_access_key: "<AWS_SECRET_ACCESS_KEY>"
    - acme_production: False
    - acme_remote_dir: "/root"
    - acme_local_cache_cert_file: "/tmp/server.cert"
    - acme_local_cache_key_file: "/tmp/server.key"
    - acme_local_cache_ca_file: "/tmp/server_ca.cer"
    - acme_cache_cert_file: "/tmp/server.cert"
    - acme_cache_key_file: "/tmp/server.key"
    - acme_cache_ca_file: "/tmp/server_ca.cer"
    - acme_cache_fullchain_file: "/tmp/fullchain.cer"
    - acme_cache_archive_file: "/tmp/acme.tar.gz"
    - acme_renew_automatically: False
    - acme_force_issue: False
@@ -94,9 +99,11 @@
    - acme_aws_secret_access_key: "<AWS_SECRET_ACCESS_KEY>"
    - acme_production: False
    - acme_remote_dir: "/root"
    - acme_local_cache_cert_file: "/tmp/server.cert"
    - acme_local_cache_key_file: "/tmp/server.key"
    - acme_local_cache_ca_file: "/tmp/server_ca.cer"
    - acme_cache_cert_file: "/tmp/server.cert"
    - acme_cache_key_file: "/tmp/server.key"
    - acme_cache_ca_file: "/tmp/server_ca.cer"
    - acme_cache_fullchain_file: "/tmp/fullchain.cer"
    - acme_cache_archive_file: "/tmp/acme.tar.gz"
    - acme_renew_automatically: False
    - acme_force_issue: False
```
ansible/roles/host-lets-encrypt-certs/defaults/main.yml
@@ -17,13 +17,14 @@
# Local (to the host ansible is running on) cache of certificates
# Prevents re-requesting certificates for later runs of the playbook
# when the domains haven't changed
acme_cache_archive_file: "/tmp/acme.tar.gz"
acme_cache_archive_file:   "/tmp/acme.tar.gz"
# If acme_local_archive_file is not provided both of the following can
# be specified to just use a previously created cert/key
acme_cache_cert_file: "/tmp/ssl.cert"
acme_cache_key_file: "/tmp/ssl.key"
acme_cache_ca_file: "/tmp/ssl_ca.cert"
acme_cache_cert_file:      "/tmp/ssl.cert"
acme_cache_key_file:       "/tmp/ssl.key"
acme_cache_ca_file:        "/tmp/ssl_ca.cert"
acme_cache_fullchain_file: "/tmp/fullchain.cer"
# Use the Production Let's Encrypt Server. Leave to False for testing runs
# to prevent issues with the Let's Encrypt rate limits
ansible/roles/host-lets-encrypt-certs/tasks/main.yml
@@ -131,6 +131,13 @@
        delegate_to: localhost
        register: cache_ca_file
      - name: Check if cached Fullchain exists
        become: False
        stat:
          path: "{{ acme_cache_fullchain_file }}"
        delegate_to: localhost
        register: cache_fullchain_file
      - name: Check that both key and certificate have been provided
        debug:
          msg: "Both Certificate and Key file need to be provided - proceeding with full setup"
@@ -161,6 +168,12 @@
            dest: "{{ acme_remote_dir }}/.acme.sh/{{ acme_domain }}/ca.cer"
          when:
          - cache_ca_file.stat.exists|bool
        - name: Copy cached Fullchain if it exists
          copy:
            src: "{{ acme_cache_fullchain_file }}"
            dest: "{{ acme_remote_dir }}/.acme.sh/{{ acme_domain }}/fullchain.cer"
          when:
          - cache_fullchain_file.stat.exists|bool
        - name: Set acme_setup_complete=true
          set_fact:
            acme_setup_complete: true
@@ -185,6 +198,14 @@
        when:
          - acme_cache_cert_file is defined and acme_cache_cert_file|trim != ""
      - name: Save fullchain.cer to cache
        fetch:
          src: "{{ acme_remote_dir }}/.acme.sh/{{ acme_domain }}/fullchain.cer"
          dest: "{{ acme_cache_fullchain_file }}"
          flat: true
        when:
          - acme_cache_fullchain_file is defined and acme_cache_fullchain_file|trim != ""
      - name: Save key to cache
        fetch:
          src: "{{ acme_remote_dir }}/.acme.sh/{{ acme_domain }}/{{ acme_domain }}.key"