diff --git a/cluster.yml b/cluster.yml
index 98bafe9780580c51fad2b2f30590cef499e1986d..5ebed30c5e4104d8fe47661db81a8276ddcf11f1 100644
--- a/cluster.yml
+++ b/cluster.yml
@@ -31,6 +31,7 @@
     - role: rkt
       tags: rkt
       when: "'rkt' in [etcd_deployment_type, kubelet_deployment_type, vault_deployment_type]"
+    - { role: download, tags: download, skip_downloads: false }
 
 - hosts: etcd:k8s-cluster:vault
   any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
diff --git a/roles/dnsmasq/meta/main.yml b/roles/dnsmasq/meta/main.yml
deleted file mode 100644
index aa0476977b2c631d34efa99dc46a8fb7b05d1bc2..0000000000000000000000000000000000000000
--- a/roles/dnsmasq/meta/main.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.dnsmasq }}"
-    when: dns_mode == 'dnsmasq_kubedns' and download_localhost|default(false)
-    tags:
-      - download
-      - dnsmasq
diff --git a/roles/download/defaults/main.yml b/roles/download/defaults/main.yml
index bbeb3070d309e552ebcdc7ca6e271bc4b0b429b2..049e49897a4dcc550c9c8631f87f2f3c5245cfa9 100644
--- a/roles/download/defaults/main.yml
+++ b/roles/download/defaults/main.yml
@@ -1,6 +1,9 @@
 ---
 local_release_dir: /tmp
 
+# Used to only evaluate vars from download role
+skip_downloads: false
+
 # if this is set to true will only download files once. Doesn't work
 # on Container Linux by CoreOS unless the download_localhost is true and localhost
 # is running another OS type. Default compress level is 1 (fastest).
@@ -17,6 +20,9 @@ download_localhost: False
 # Always pull images if set to True. Otherwise check by the repo's tag/digest.
 download_always_pull: False
 
+# Use the first kube-master if download_localhost is not set
+download_delegate: "{% if download_localhost %}localhost{% else %}{{groups['kube-master'][0]}}{% endif %}"
+
 # Versions
 kube_version: v1.8.0
 kubeadm_version: "{{ kube_version }}"
@@ -44,6 +50,13 @@ istio_version: "0.2.6"
 istioctl_download_url: "https://storage.googleapis.com/istio-release/releases/{{ istio_version }}/istioctl/istioctl-linux"
 istioctl_checksum: fd703063c540b8c0ab943f478c05ab257d88ae27224c746a27d0526ddbf7c370
 
+vault_version: 0.8.1
+vault_binary_checksum: 3c4d70ba71619a43229e65c67830e30e050eab7a81ac6b28325ff707e5914188
+vault_download_url: "https://releases.hashicorp.com/vault/{{ vault_version }}/vault_{{ vault_version }}_linux_amd64.zip"
+vault_image_repo: "vault"
+vault_image_tag: "{{ vault_version }}"
+
+
 # Containers
 etcd_image_repo: "quay.io/coreos/etcd"
 etcd_image_tag: "{{ etcd_version }}"
@@ -113,23 +126,26 @@ tiller_image_tag: "{{ tiller_version }}"
 
 downloads:
   netcheck_server:
+    enabled: "{{ deploy_netchecker }}"
     container: true
     repo: "{{ netcheck_server_img_repo }}"
     tag: "{{ netcheck_server_tag }}"
     sha256: "{{ netcheck_server_digest_checksum|default(None) }}"
-    enabled: "{{ deploy_netchecker|bool }}"
   netcheck_agent:
+    enabled: "{{ deploy_netchecker }}"
     container: true
     repo: "{{ netcheck_agent_img_repo }}"
     tag: "{{ netcheck_agent_tag }}"
     sha256: "{{ netcheck_agent_digest_checksum|default(None) }}"
-    enabled: "{{ deploy_netchecker|bool }}"
   etcd:
+    enabled: true
     container: true
     repo: "{{ etcd_image_repo }}"
     tag: "{{ etcd_image_tag }}"
     sha256: "{{ etcd_digest_checksum|default(None) }}"
   kubeadm:
+    enabled: "{{ kubeadm_enabled }}"
+    file: true
     version: "{{ kubeadm_version }}"
     dest: "kubeadm"
     sha256: "{{ kubeadm_checksum }}"
@@ -139,6 +155,8 @@ downloads:
     owner: "root"
     mode: "0755"
   istioctl:
+    enabled: "{{ istio_enabled }}"
+    file: true
     version: "{{ istio_version }}"
     dest: "istio/istioctl"
     sha256: "{{ istioctl_checksum }}"
@@ -148,145 +166,173 @@ downloads:
     owner: "root"
     mode: "0755"
   hyperkube:
+    enabled: true
     container: true
     repo: "{{ hyperkube_image_repo }}"
     tag: "{{ hyperkube_image_tag }}"
     sha256: "{{ hyperkube_digest_checksum|default(None) }}"
   flannel:
+    enabled: "{{ kube_network_plugin == 'flannel' or kube_network_plugin == 'canal' }}"
     container: true
     repo: "{{ flannel_image_repo }}"
     tag: "{{ flannel_image_tag }}"
     sha256: "{{ flannel_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'flannel' or kube_network_plugin == 'canal' }}"
   flannel_cni:
+    enabled: "{{ kube_network_plugin == 'flannel' }}"
     container: true
     repo: "{{ flannel_cni_image_repo }}"
     tag: "{{ flannel_cni_image_tag }}"
     sha256: "{{ flannel_cni_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'flannel' }}"
   calicoctl:
+    enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
     container: true
     repo: "{{ calicoctl_image_repo }}"
     tag: "{{ calicoctl_image_tag }}"
     sha256: "{{ calicoctl_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
   calico_node:
+    enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
     container: true
     repo: "{{ calico_node_image_repo }}"
     tag: "{{ calico_node_image_tag }}"
     sha256: "{{ calico_node_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
   calico_cni:
+    enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
     container: true
     repo: "{{ calico_cni_image_repo }}"
     tag: "{{ calico_cni_image_tag }}"
     sha256: "{{ calico_cni_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
   calico_policy:
+    enabled: "{{ enable_network_policy or kube_network_plugin == 'canal' }}"
     container: true
     repo: "{{ calico_policy_image_repo }}"
     tag: "{{ calico_policy_image_tag }}"
     sha256: "{{ calico_policy_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'canal' }}"
   calico_rr:
+    enabled: "{{ peer_with_calico_rr is defined and peer_with_calico_rr}} and kube_network_plugin == 'calico'"
     container: true
     repo: "{{ calico_rr_image_repo }}"
     tag: "{{ calico_rr_image_tag }}"
     sha256: "{{ calico_rr_digest_checksum|default(None) }}"
-    enabled: "{{ peer_with_calico_rr is defined and peer_with_calico_rr}} and kube_network_plugin == 'calico'"
   weave_kube:
+    enabled: "{{ kube_network_plugin == 'weave' }}"
     container: true
     repo: "{{ weave_kube_image_repo }}"
     tag: "{{ weave_kube_image_tag }}"
     sha256: "{{ weave_kube_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'weave' }}"
   weave_npc:
+    enabled: "{{ kube_network_plugin == 'weave' }}"
     container: true
     repo: "{{ weave_npc_image_repo }}"
     tag: "{{ weave_npc_image_tag }}"
     sha256: "{{ weave_npc_digest_checksum|default(None) }}"
-    enabled: "{{ kube_network_plugin == 'weave' }}"
   pod_infra:
+    enabled: true
     container: true
     repo: "{{ pod_infra_image_repo }}"
     tag: "{{ pod_infra_image_tag }}"
     sha256: "{{ pod_infra_digest_checksum|default(None) }}"
   install_socat:
+    enabled: "{{ ansible_os_family in ['CoreOS', 'Container Linux by CoreOS'] }}"
     container: true
     repo: "{{ install_socat_image_repo }}"
     tag: "{{ install_socat_image_tag }}"
     sha256: "{{ install_socat_digest_checksum|default(None) }}"
   nginx:
+    enabled: true
     container: true
     repo: "{{ nginx_image_repo }}"
     tag: "{{ nginx_image_tag }}"
     sha256: "{{ nginx_digest_checksum|default(None) }}"
   dnsmasq:
+    enabled: "{{ dns_mode == 'dnsmasq_kubedns' }}"
     container: true
     repo: "{{ dnsmasq_image_repo }}"
     tag: "{{ dnsmasq_image_tag }}"
     sha256: "{{ dnsmasq_digest_checksum|default(None) }}"
   kubedns:
+    enabled: true
     container: true
     repo: "{{ kubedns_image_repo }}"
     tag: "{{ kubedns_image_tag }}"
     sha256: "{{ kubedns_digest_checksum|default(None) }}"
   dnsmasq_nanny:
+    enabled: true
     container: true
     repo: "{{ dnsmasq_nanny_image_repo }}"
     tag: "{{ dnsmasq_nanny_image_tag }}"
     sha256: "{{ dnsmasq_nanny_digest_checksum|default(None) }}"
   dnsmasq_sidecar:
+    enabled: true
     container: true
     repo: "{{ dnsmasq_sidecar_image_repo }}"
     tag: "{{ dnsmasq_sidecar_image_tag }}"
     sha256: "{{ dnsmasq_sidecar_digest_checksum|default(None) }}"
   kubednsautoscaler:
+    enabled: true
     container: true
     repo: "{{ kubednsautoscaler_image_repo }}"
     tag: "{{ kubednsautoscaler_image_tag }}"
     sha256: "{{ kubednsautoscaler_digest_checksum|default(None) }}"
   testbox:
+    enabled: true
     container: true
     repo: "{{ test_image_repo }}"
     tag: "{{ test_image_tag }}"
     sha256: "{{ testbox_digest_checksum|default(None) }}"
   elasticsearch:
+    enabled: "{{ efk_enabled }}"
     container: true
     repo: "{{ elasticsearch_image_repo }}"
     tag: "{{ elasticsearch_image_tag }}"
     sha256: "{{ elasticsearch_digest_checksum|default(None) }}"
   fluentd:
+    enabled: "{{ efk_enabled }}"
     container: true
     repo: "{{ fluentd_image_repo }}"
     tag: "{{ fluentd_image_tag }}"
     sha256: "{{ fluentd_digest_checksum|default(None) }}"
   kibana:
+    enabled: "{{ efk_enabled }}"
     container: true
     repo: "{{ kibana_image_repo }}"
     tag: "{{ kibana_image_tag }}"
     sha256: "{{ kibana_digest_checksum|default(None) }}"
   helm:
+    enabled: "{{ helm_enabled }}"
     container: true
     repo: "{{ helm_image_repo }}"
     tag: "{{ helm_image_tag }}"
     sha256: "{{ helm_digest_checksum|default(None) }}"
   tiller:
+    enabled: "{{ helm_enabled }}"
     container: true
     repo: "{{ tiller_image_repo }}"
     tag: "{{ tiller_image_tag }}"
     sha256: "{{ tiller_digest_checksum|default(None) }}"
+  vault:
+    enabled: "{{ cert_management == 'vault' }}"
+    container: "{{ vault_deployment_type != 'host' }}"
+    file: "{{ vault_deployment_type == 'host' }}"
+    dest: "vault/vault_{{ vault_version }}_linux_amd64.zip"
+    mode: "0755"
+    owner: "vault"
+    repo: "{{ vault_image_repo }}"
+    sha256: "{{ vault_binary_checksum if vault_deployment_type == 'host' else vault_digest_checksum|d(none) }}"
+    source_url: "{{ vault_download_url }}"
+    tag: "{{ vault_image_tag }}"
+    unarchive: true
+    url: "{{ vault_download_url }}"
+    version: "{{ vault_version }}"
 
-download:
-  container: "{{ file.container|default(false) }}"
-  repo: "{{ file.repo|default(None) }}"
-  tag: "{{ file.tag|default(None) }}"
-  enabled: "{{ file.enabled|default(true) }}"
-  dest: "{{ file.dest|default(None) }}"
-  version: "{{ file.version|default(None) }}"
-  sha256: "{{ file.sha256|default(None) }}"
-  source_url: "{{ file.source_url|default(None) }}"
-  url: "{{ file.url|default(None) }}"
-  unarchive: "{{ file.unarchive|default(false) }}"
-  owner: "{{ file.owner|default('kube') }}"
-  mode: "{{ file.mode|default(None) }}"
+download_defaults:
+  container: false
+  file: false
+  repo: None
+  tag: None
+  enabled: false
+  dest: None
+  version: None
+  url: None
+  unarchive: false
+  owner: kube
+  mode: None
diff --git a/roles/download/meta/main.yml b/roles/download/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..61d3ffe4f9416869d4fff5118f784dd567977025
--- /dev/null
+++ b/roles/download/meta/main.yml
@@ -0,0 +1,2 @@
+---
+allow_duplicates: true
diff --git a/roles/download/tasks/download_container.yml b/roles/download/tasks/download_container.yml
new file mode 100644
index 0000000000000000000000000000000000000000..df621aadeddb11bdead6a17e83f42ef375075e72
--- /dev/null
+++ b/roles/download/tasks/download_container.yml
@@ -0,0 +1,26 @@
+---
+- name: container_download | Make download decision if pull is required by tag or sha256
+  include: set_docker_image_facts.yml
+  delegate_to: "{{ download_delegate if download_run_once or omit }}"
+  delegate_facts: no
+  run_once: "{{ download_run_once }}"
+  when:
+    - download.enabled
+    - download.container
+  tags:
+    - facts
+
+- name: container_download | Download containers if pull is required or told to always pull
+  command: "{{ docker_bin_dir }}/docker pull {{ pull_args }}"
+  register: pull_task_result
+  until: pull_task_result|succeeded
+  retries: 4
+  delay: "{{ retry_stagger | random + 3 }}"
+  environment: "{{ proxy_env }}"
+  when:
+    - download.enabled
+    - download.container
+    - pull_required|default(download_always_pull)
+  delegate_to: "{{ download_delegate if download_run_once or omit }}"
+  delegate_facts: no
+  run_once: "{{ download_run_once }}"
diff --git a/roles/download/tasks/download_file.yml b/roles/download/tasks/download_file.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dfbfc348d0192ac32835753602c2aa173b9647e9
--- /dev/null
+++ b/roles/download/tasks/download_file.yml
@@ -0,0 +1,37 @@
+---
+- name: file_download | Create dest directory
+  file:
+    path: "{{local_release_dir}}/{{download.dest|dirname}}"
+    state: directory
+    recurse: yes
+  when:
+    - download.enabled
+    - download.file
+
+- name: file_download | Download item
+  get_url:
+    url: "{{download.url}}"
+    dest: "{{local_release_dir}}/{{download.dest}}"
+    sha256sum: "{{download.sha256 | default(omit)}}"
+    owner: "{{ download.owner|default(omit) }}"
+    mode: "{{ download.mode|default(omit) }}"
+  register: get_url_result
+  until: "'OK' in get_url_result.msg or 'file already exists' in get_url_result.msg"
+  retries: 4
+  delay: "{{ retry_stagger | random + 3 }}"
+  environment: "{{ proxy_env }}"
+  when:
+    - download.enabled
+    - download.file
+
+- name: file_download | Extract archives
+  unarchive:
+    src: "{{ local_release_dir }}/{{download.dest}}"
+    dest: "{{ local_release_dir }}/{{download.dest|dirname}}"
+    owner: "{{ download.owner|default(omit) }}"
+    mode: "{{ download.mode|default(omit) }}"
+    copy: no
+  when:
+    - download.enabled
+    - download.file
+    - download.unarchive|default(False)
diff --git a/roles/download/tasks/download_prep.yml b/roles/download/tasks/download_prep.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1fd7abf2fb29a77a8332a9ba5f78117f1953e85e
--- /dev/null
+++ b/roles/download/tasks/download_prep.yml
@@ -0,0 +1,32 @@
+---
+- name: Register docker images info
+  raw: >-
+    {{ docker_bin_dir }}/docker images -q | xargs {{ docker_bin_dir }}/docker inspect -f "{{ '{{' }} (index .RepoTags 0) {{ '}}' }},{{ '{{' }} (index .RepoDigests 0) {{ '}}' }}" | tr '\n' ','
+  no_log: true
+  register: docker_images
+  failed_when: false
+  changed_when: false
+  check_mode: no
+
+- name: container_download | Create dest directory for saved/loaded container images
+  file:
+    path: "{{local_release_dir}}/containers"
+    state: directory
+    recurse: yes
+    mode: 0755
+    owner: "{{ansible_ssh_user|default(ansible_user_id)}}"
+
+- name: container_download | create local directory for saved/loaded container images
+  file:
+    path: "{{local_release_dir}}/containers"
+    state: directory
+    recurse: yes
+  delegate_to: localhost
+  delegate_facts: false
+  become: false
+  run_once: true
+  when:
+    - download_run_once
+    - download_delegate == 'localhost'
+  tags:
+    - localhost
diff --git a/roles/download/tasks/main.yml b/roles/download/tasks/main.yml
index d8db2cc2c1033c49ffaebd1bafb5ac72753be08f..f26429e1e1a28dd107fa4d9250d12546b5c97199 100644
--- a/roles/download/tasks/main.yml
+++ b/roles/download/tasks/main.yml
@@ -1,218 +1,24 @@
 ---
-- name: file_download | Create dest directories
-  file:
-    path: "{{local_release_dir}}/{{download.dest|dirname}}"
-    state: directory
-    recurse: yes
+- import_tasks: download_prep.yml
   when:
-    - download.enabled|bool
-    - not download.container|bool
-  tags:
-    - bootstrap-os
+    - not skip_downloads|default(false)
 
-- name: file_download | Download item
-  get_url:
-    url: "{{download.url}}"
-    dest: "{{local_release_dir}}/{{download.dest}}"
-    sha256sum: "{{download.sha256 | default(omit)}}"
-    owner: "{{ download.owner|default(omit) }}"
-    mode: "{{ download.mode|default(omit) }}"
-  register: get_url_result
-  until: "'OK' in get_url_result.msg or 'file already exists' in get_url_result.msg"
-  retries: 4
-  delay: "{{ retry_stagger | random + 3 }}"
-  environment: "{{ proxy_env }}"
+- name: "Download items"
+  include: "download_{% if download.container %}container{% else %}file{% endif %}.yml"
+  vars:
+    download: "{{ download_defaults | combine(item.value) }}"
+  with_dict: "{{ downloads }}"
   when:
-    - download.enabled|bool
-    - not download.container|bool
+    - not skip_downloads|default(false)
+    - item.enabled
 
-- name: file_download | Extract archives
-  unarchive:
-    src: "{{ local_release_dir }}/{{download.dest}}"
-    dest: "{{ local_release_dir }}/{{download.dest|dirname}}"
-    owner: "{{ download.owner|default(omit) }}"
-    mode: "{{ download.mode|default(omit) }}"
-    copy: no
+- name: "Sync container"
+  include: sync_container.yml
+  vars:
+    download: "{{ download_defaults | combine(item.value) }}"
+  with_dict: "{{ downloads }}"
   when:
-    - download.enabled|bool
-    - not download.container|bool
-    - download.unarchive|default(False)
-
-- name: file_download | Fix permissions
-  file:
-    state: file
-    path: "{{local_release_dir}}/{{download.dest}}"
-    owner: "{{ download.owner|default(omit) }}"
-    mode: "{{ download.mode|default(omit) }}"
-  when:
-    - download.enabled|bool
-    - not download.container|bool
-    - (download.unarchive is not defined or download.unarchive == False)
-
-- set_fact:
-    download_delegate: "{% if download_localhost|bool %}localhost{% else %}{{groups['kube-master'][0]}}{% endif %}"
-  run_once: true
-  tags:
-    - facts
-
-- name: container_download | Create dest directory for saved/loaded container images
-  file:
-    path: "{{local_release_dir}}/containers"
-    state: directory
-    recurse: yes
-    mode: 0755
-    owner: "{{ansible_ssh_user|default(ansible_user_id)}}"
-  when:
-    - download.enabled|bool
-    - download.container|bool
-  tags:
-    - bootstrap-os
-
-# This is required for the download_localhost delegate to work smooth with Container Linux by CoreOS cluster nodes
-- name: container_download | Hack python binary path for localhost
-  raw: sh -c "mkdir -p /opt/bin; ln -sf /usr/bin/python /opt/bin/python"
-  delegate_to: localhost
-  when: download_delegate == 'localhost'
-  failed_when: false
-  tags:
-    - localhost
-
-- name: container_download | create local directory for saved/loaded container images
-  file:
-    path: "{{local_release_dir}}/containers"
-    state: directory
-    recurse: yes
-  delegate_to: localhost
-  become: false
-  run_once: true
-  when:
-    - download_run_once|bool
-    - download.enabled|bool
-    - download.container|bool
-    - download_delegate == 'localhost'
-  tags:
-    - localhost
-
-- name: container_download | Make download decision if pull is required by tag or sha256
-  include: set_docker_image_facts.yml
-  when:
-    - download.enabled|bool
-    - download.container|bool
-  delegate_to: "{{ download_delegate if download_run_once|bool or omit }}"
-  run_once: "{{ download_run_once|bool }}"
-  tags:
-    - facts
-
-- name: container_download | Download containers if pull is required or told to always pull
-  command: "{{ docker_bin_dir }}/docker pull {{ pull_args }}"
-  register: pull_task_result
-  until: pull_task_result|succeeded
-  retries: 4
-  delay: "{{ retry_stagger | random + 3 }}"
-  environment: "{{ proxy_env }}"
-  when:
-    - download.enabled|bool
-    - download.container|bool
-    - pull_required|bool|default(download_always_pull)
-  delegate_to: "{{ download_delegate if download_run_once|bool or omit }}"
-  run_once: "{{ download_run_once|bool }}"
-
-- set_fact:
-    fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|default(download.sha256)|regex_replace('/|\0|:', '_')}}.tar"
-  run_once: true
-  tags:
-    - facts
-
-- name: "container_download | Set default value for 'container_changed' to false"
-  set_fact:
-    container_changed: "{{pull_required|default(false)|bool}}"
-
-- name: "container_download | Update the 'container_changed' fact"
-  set_fact:
-    container_changed: "{{ pull_required|bool|default(false) or not 'up to date' in pull_task_result.stdout }}"
-  when:
-    - download.enabled|bool
-    - download.container|bool
-    - pull_required|bool|default(download_always_pull)
-  run_once: "{{ download_run_once|bool }}"
-  tags:
-    - facts
-
-- name: container_download | Stat saved container image
-  stat:
-    path: "{{fname}}"
-  register: img
-  changed_when: false
-  when:
-    - download.enabled|bool
-    - download.container|bool
-    - download_run_once|bool
-  delegate_to: "{{ download_delegate }}"
-  become: false
-  run_once: true
-  tags:
-    - facts
-
-- name: container_download | save container images
-  shell: "{{ docker_bin_dir }}/docker save {{ pull_args }} | gzip -{{ download_compress }} > {{ fname }}"
-  delegate_to: "{{ download_delegate }}"
-  register: saved
-  run_once: true
-  when:
-    - (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] or download_delegate == "localhost")
-    - download_run_once|bool
-    - download.enabled|bool
-    - download.container|bool
-    - (container_changed|bool or not img.stat.exists)
-
-- name: container_download | copy container images to ansible host
-  synchronize:
-    src: "{{ fname }}"
-    dest: "{{ fname }}"
-    use_ssh_args: yes
-    mode: pull
-  delegate_to: localhost
-  become: false
-  when:
-    - not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
-    - inventory_hostname == groups['kube-master'][0]
-    - download_delegate != "localhost"
-    - download_run_once|bool
-    - download.enabled|bool
-    - download.container|bool
-    - saved.changed
-
-- name: container_download | upload container images to nodes
-  synchronize:
-    src: "{{ fname }}"
-    dest: "{{ fname }}"
-    use_ssh_args: yes
-    mode: push
-  delegate_to: localhost
-  become: false
-  register: get_task
-  until: get_task|succeeded
-  retries: 4
-  delay: "{{ retry_stagger | random + 3 }}"
-  when:
-    - (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and
-      inventory_hostname != groups['kube-master'][0] or
-      download_delegate == "localhost")
-    - download_run_once|bool
-    - download.enabled|bool
-    - download.container|bool
-  tags:
-    - upload
-    - upgrade
-
-- name: container_download | load container images
-  shell: "{{ docker_bin_dir }}/docker load < {{ fname }}"
-  when:
-    - (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and
-      inventory_hostname != groups['kube-master'][0] or download_delegate == "localhost")
-    - download_run_once|bool
-    - download.enabled|bool
-    - download.container|bool
-  tags:
-    - upload
-    - upgrade
+    - not skip_downloads|default(false)
+    - item.enabled
+    - item.container
+    - download_run_once
diff --git a/roles/download/tasks/set_docker_image_facts.yml b/roles/download/tasks/set_docker_image_facts.yml
index eabddcbb470287fc35866bb696b2e0ffb8a59a85..7a9b73e38b56e39f74a15113b50cf40bf46b8b11 100644
--- a/roles/download/tasks/set_docker_image_facts.yml
+++ b/roles/download/tasks/set_docker_image_facts.yml
@@ -5,7 +5,7 @@
 
 - set_fact:
     pull_args: >-
-      {%- if pull_by_digest|bool %}{{download.repo}}@sha256:{{download.sha256}}{%- else -%}{{download.repo}}:{{download.tag}}{%- endif -%}
+      {%- if pull_by_digest %}{{download.repo}}@sha256:{{download.sha256}}{%- else -%}{{download.repo}}:{{download.tag}}{%- endif -%}
 
 - name: Register docker images info
   raw: >-
@@ -15,16 +15,16 @@
   failed_when: false
   changed_when: false
   check_mode: no
-  when: not download_always_pull|bool
+  when: not download_always_pull
 
 - set_fact:
     pull_required: >-
       {%- if pull_args in docker_images.stdout.split(',') %}false{%- else -%}true{%- endif -%}
-  when: not download_always_pull|bool
+  when: not download_always_pull
 
 - name: Check the local digest sha256 corresponds to the given image tag
   assert:
     that: "{{download.repo}}:{{download.tag}} in docker_images.stdout.split(',')"
-  when: not download_always_pull|bool and not pull_required|bool and pull_by_digest|bool
+  when: not download_always_pull and not pull_required and pull_by_digest
   tags:
     - asserts
diff --git a/roles/download/tasks/sync_container.yml b/roles/download/tasks/sync_container.yml
new file mode 100644
index 0000000000000000000000000000000000000000..146706543edb000c7a2fa94135a11689705daba1
--- /dev/null
+++ b/roles/download/tasks/sync_container.yml
@@ -0,0 +1,114 @@
+---
+- set_fact:
+    fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|default(download.sha256)|regex_replace('/|\0|:', '_')}}.tar"
+  run_once: true
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+  tags:
+    - facts
+
+- name: "container_download | Set default value for 'container_changed' to false"
+  set_fact:
+    container_changed: "{{pull_required|default(false)}}"
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+
+- name: "container_download | Update the 'container_changed' fact"
+  set_fact:
+    container_changed: "{{ pull_required|default(false) or not 'up to date' in pull_task_result.stdout }}"
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+    - pull_required|default(download_always_pull)
+  run_once: "{{ download_run_once }}"
+  tags:
+    - facts
+
+- name: container_download | Stat saved container image
+  stat:
+    path: "{{fname}}"
+  register: img
+  changed_when: false
+  delegate_to: "{{ download_delegate }}"
+  delegate_facts: no
+  become: false
+  run_once: true
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+  tags:
+    - facts
+
+- name: container_download | save container images
+  shell: "{{ docker_bin_dir }}/docker save {{ pull_args }} | gzip -{{ download_compress }} > {{ fname }}"
+  delegate_to: "{{ download_delegate }}"
+  delegate_facts: no
+  register: saved
+  run_once: true
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+    - (ansible_os_family not in ["CoreOS", "Container Linux by CoreOS"] or download_delegate == "localhost")
+    - (container_changed or not img.stat.exists)
+
+- name: container_download | copy container images to ansible host
+  synchronize:
+    src: "{{ fname }}"
+    dest: "{{ fname }}"
+    use_ssh_args: yes
+    mode: pull
+  delegate_to: localhost
+  delegate_facts: no
+  run_once: true
+  become: false
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+    - ansible_os_family not in ["CoreOS", "Container Linux by CoreOS"]
+    - inventory_hostname == download_delegate
+    - download_delegate != "localhost"
+    - saved.changed
+
+- name: container_download | upload container images to nodes
+  synchronize:
+    src: "{{ fname }}"
+    dest: "{{ fname }}"
+    use_ssh_args: yes
+    mode: push
+  delegate_to: localhost
+  delegate_facts: no
+  become: false
+  register: get_task
+  until: get_task|succeeded
+  retries: 4
+  delay: "{{ retry_stagger | random + 3 }}"
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+    - (ansible_os_family not in ["CoreOS", "Container Linux by CoreOS"] and
+      inventory_hostname != download_delegate or
+      download_delegate == "localhost")
+  tags:
+    - upload
+    - upgrade
+
+- name: container_download | load container images
+  shell: "{{ docker_bin_dir }}/docker load < {{ fname }}"
+  when:
+    - download.enabled
+    - download.container
+    - download_run_once
+    - (ansible_os_family not in ["CoreOS", "Container Linux by CoreOS"] and
+      inventory_hostname != download_delegate or download_delegate == "localhost")
+  tags:
+    - upload
+    - upgrade
diff --git a/roles/etcd/meta/main.yml b/roles/etcd/meta/main.yml
index 5e6e581c250d89d10d2e1653f5aa5542c28abcf9..c59df8af00ccf31bbc52670f7005c0ddfb59c73a 100644
--- a/roles/etcd/meta/main.yml
+++ b/roles/etcd/meta/main.yml
@@ -4,9 +4,4 @@ dependencies:
     user: "{{ addusers.etcd }}"
     when: not (ansible_os_family in ['CoreOS', 'Container Linux by CoreOS'] or is_atomic)
 
-  - role: download
-    file: "{{ downloads.etcd }}"
-    tags:
-      - download
-
 # NOTE: Dynamic task dependency on Vault Role if cert_management == "vault"
diff --git a/roles/kubernetes-apps/efk/elasticsearch/meta/main.yml b/roles/kubernetes-apps/efk/elasticsearch/meta/main.yml
index 3dc6f3ca125d2be7b346ceb7fc44d841a4e6e83f..0fa1b05d8393863140fc02efebd65bca352e8b03 100644
--- a/roles/kubernetes-apps/efk/elasticsearch/meta/main.yml
+++ b/roles/kubernetes-apps/efk/elasticsearch/meta/main.yml
@@ -1,7 +1,4 @@
 ---
-dependencies:
-  - role: download
-    file: "{{ downloads.elasticsearch }}"
 # TODO: bradbeam add in curator
 #       https://github.com/Skillshare/kubernetes-efk/blob/master/configs/elasticsearch.yml#L94
 #  - role: download
diff --git a/roles/kubernetes-apps/efk/fluentd/meta/main.yml b/roles/kubernetes-apps/efk/fluentd/meta/main.yml
deleted file mode 100644
index 0e1e03813307e0b1b4e5f18f642ad4a30f23c081..0000000000000000000000000000000000000000
--- a/roles/kubernetes-apps/efk/fluentd/meta/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.fluentd }}"
diff --git a/roles/kubernetes-apps/efk/kibana/meta/main.yml b/roles/kubernetes-apps/efk/kibana/meta/main.yml
deleted file mode 100644
index 775880d545f4af2bb211906e98ba2f5ed5c924c9..0000000000000000000000000000000000000000
--- a/roles/kubernetes-apps/efk/kibana/meta/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.kibana }}"
diff --git a/roles/kubernetes-apps/helm/meta/main.yml b/roles/kubernetes-apps/helm/meta/main.yml
deleted file mode 100644
index 5092ec83b18ab32f6d8b7097db0bbd8a35b62d5b..0000000000000000000000000000000000000000
--- a/roles/kubernetes-apps/helm/meta/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.helm }}"
-  - role: download
-    file: "{{ downloads.tiller }}"
diff --git a/roles/kubernetes-apps/istio/meta/main.yml b/roles/kubernetes-apps/istio/meta/main.yml
deleted file mode 100644
index 97c4df2a023c7a95222f8aefd7dff3872051dd2a..0000000000000000000000000000000000000000
--- a/roles/kubernetes-apps/istio/meta/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.istioctl }}"
diff --git a/roles/kubernetes-apps/meta/main.yml b/roles/kubernetes-apps/meta/main.yml
index f8866c42c8dde95f9ebdca151d51ce0a015dbe8c..13aa11e75309c772c57d4c15808c8e97cf40f2b7 100644
--- a/roles/kubernetes-apps/meta/main.yml
+++ b/roles/kubernetes-apps/meta/main.yml
@@ -1,19 +1,5 @@
 ---
 dependencies:
-  - role: download
-    file: "{{ downloads.netcheck_server }}"
-    when: deploy_netchecker
-    tags:
-      - download
-      - netchecker
-
-  - role: download
-    file: "{{ downloads.netcheck_agent }}"
-    when: deploy_netchecker
-    tags:
-      - download
-      - netchecker
-
   - role: kubernetes-apps/ansible
     tags:
       - apps
diff --git a/roles/kubernetes-apps/policy_controller/meta/main.yml b/roles/kubernetes-apps/policy_controller/meta/main.yml
index 10838db0bca3a883555a96ff2eba4dd117b82d56..91cb0276c133508c09dccf1566643b288ede0aff 100644
--- a/roles/kubernetes-apps/policy_controller/meta/main.yml
+++ b/roles/kubernetes-apps/policy_controller/meta/main.yml
@@ -1,15 +1,5 @@
 ---
 dependencies:
-  - role: download
-    file: "{{ downloads.calico_policy }}"
-    when:
-      - enable_network_policy
-      - kube_network_plugin in ['calico', 'canal']
-    tags:
-      - download
-      - canal
-      - policy-controller
-
   - role: policy_controller/calico
     when:
       - kube_network_plugin == 'calico'
diff --git a/roles/kubernetes/master/meta/main.yml b/roles/kubernetes/master/meta/main.yml
deleted file mode 100644
index 204421fc527057ad98e17af9dcb1f0813c13218f..0000000000000000000000000000000000000000
--- a/roles/kubernetes/master/meta/main.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.hyperkube }}"
-    tags:
-      - download
-      - hyperkube
diff --git a/roles/kubernetes/node/meta/main.yml b/roles/kubernetes/node/meta/main.yml
index f62228856c36101a9bcaaa59b1dbdf4db72b9454..00c3c9fe2017219d364a2ff45452b83529694b08 100644
--- a/roles/kubernetes/node/meta/main.yml
+++ b/roles/kubernetes/node/meta/main.yml
@@ -1,91 +1,6 @@
 ---
 dependencies:
-  - role: download
-    file: "{{ downloads.hyperkube }}"
-    tags:
-      - download
-      - hyperkube
-      - kubelet
-      - network
-      - canal
-      - calico
-      - weave
-      - kube-controller-manager
-      - kube-scheduler
-      - kube-apiserver
-      - kube-proxy
-      - kubectl
-
-  - role: download
-    file: "{{ downloads.pod_infra }}"
-    tags:
-      - download
-      - kubelet
-
-  - role: download
-    file: "{{ downloads.install_socat }}"
-    when: ansible_os_family in ['CoreOS', 'Container Linux by CoreOS']
-    tags:
-      - download
-      - kubelet
-
-  - role: download
-    file: "{{ downloads.kubeadm }}"
-    when: kubeadm_enabled
-    tags:
-      - download
-      - kubelet
-      - kubeadm
-
   - role: kubernetes/secrets
     when: not kubeadm_enabled
     tags:
       - k8s-secrets
-  - role: download
-    file: "{{ downloads.nginx }}"
-    tags:
-      - download
-      - nginx
-
-  - role: download
-    file: "{{ downloads.testbox }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.netcheck_server }}"
-    when: deploy_netchecker
-    tags:
-      - download
-      - netchecker
-
-  - role: download
-    file: "{{ downloads.netcheck_agent }}"
-    when: deploy_netchecker
-    tags:
-      - download
-      - netchecker
-
-  - role: download
-    file: "{{ downloads.kubedns }}"
-    tags:
-      - download
-      - dnsmasq
-
-  - role: download
-    file: "{{ downloads.dnsmasq_nanny }}"
-    tags:
-      - download
-      - dnsmasq
-
-  - role: download
-    file: "{{ downloads.dnsmasq_sidecar }}"
-    tags:
-      - download
-      - dnsmasq
-
-  - role: download
-    file: "{{ downloads.kubednsautoscaler }}"
-    tags:
-      - download
-      - dnsmasq
diff --git a/roles/kubespray-defaults/defaults/main.yaml b/roles/kubespray-defaults/defaults/main.yaml
index 9b5eced94306a5c36f1b3e3564cb0461eb61781e..5de9e42e215789f0f1683d9d72e203096ffe77e5 100644
--- a/roles/kubespray-defaults/defaults/main.yaml
+++ b/roles/kubespray-defaults/defaults/main.yaml
@@ -132,6 +132,8 @@ kubectl_localhost: false
 # K8s image pull policy (imagePullPolicy)
 k8s_image_pull_policy: IfNotPresent
 efk_enabled: false
+helm_enabled: false
+istio_enabled: false
 enable_network_policy: false
 
 ## When OpenStack is used, Cinder version can be explicitly specified if autodetection fails (https://github.com/kubernetes/kubernetes/issues/50461)
diff --git a/roles/kubespray-defaults/meta/main.yml b/roles/kubespray-defaults/meta/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..88d70247e5f638e26d64ba9241ed57445efd613b
--- /dev/null
+++ b/roles/kubespray-defaults/meta/main.yml
@@ -0,0 +1,6 @@
+---
+dependencies:
+  - role: download
+    skip_downloads: true
+    tags:
+      - facts
diff --git a/roles/network_plugin/calico/meta/main.yml b/roles/network_plugin/calico/meta/main.yml
deleted file mode 100644
index d8d1a6d4c94b5c4284fd648fe453d567d8d907e4..0000000000000000000000000000000000000000
--- a/roles/network_plugin/calico/meta/main.yml
+++ /dev/null
@@ -1,21 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.calico_cni }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.calico_node }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.calicoctl }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.hyperkube }}"
-    tags:
-      - download
diff --git a/roles/network_plugin/calico/rr/meta/main.yml b/roles/network_plugin/calico/rr/meta/main.yml
deleted file mode 100644
index 511b89744cdb3331acb4a946236362e2164b7836..0000000000000000000000000000000000000000
--- a/roles/network_plugin/calico/rr/meta/main.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-dependencies:
-  - role: etcd
-  - role: docker
-    when: not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
-  - role: download
-    file: "{{ downloads.calico_rr }}"
diff --git a/roles/network_plugin/canal/meta/main.yml b/roles/network_plugin/canal/meta/main.yml
deleted file mode 100644
index 8bbc3cb6e1d0be71c6711cea8cf932e9b93578b7..0000000000000000000000000000000000000000
--- a/roles/network_plugin/canal/meta/main.yml
+++ /dev/null
@@ -1,26 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.flannel }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.calico_node }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.calicoctl }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.calico_cni }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.calico_policy }}"
-    tags:
-      - download
diff --git a/roles/network_plugin/flannel/meta/main.yml b/roles/network_plugin/flannel/meta/main.yml
deleted file mode 100644
index 7ee3ba96fb0d2e4dd8c5b45a9904fb836c0eecba..0000000000000000000000000000000000000000
--- a/roles/network_plugin/flannel/meta/main.yml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.flannel }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.flannel_cni }}"
-    tags:
-      - download
diff --git a/roles/network_plugin/weave/meta/main.yml b/roles/network_plugin/weave/meta/main.yml
deleted file mode 100644
index a0e93bc364e2c52a16e98727945773606b7c1ad3..0000000000000000000000000000000000000000
--- a/roles/network_plugin/weave/meta/main.yml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-dependencies:
-  - role: download
-    file: "{{ downloads.weave_kube }}"
-    tags:
-      - download
-
-  - role: download
-    file: "{{ downloads.weave_npc }}"
-    tags:
-      - download
diff --git a/roles/vault/meta/main.yml b/roles/vault/meta/main.yml
index f8e993bcb692c75fd4bd3eb9975d2d05f6d63edd..fb415f9a312064d4b228fbbefb66ebb6f4a055c9 100644
--- a/roles/vault/meta/main.yml
+++ b/roles/vault/meta/main.yml
@@ -1,10 +1,4 @@
 ---
-
 dependencies:
   - role: adduser
     user: "{{ vault_adduser_vars }}"
-
-  - role: download
-    file: "{{ vault_download_vars }}"
-    tags:
-      - download