diff --git a/Vagrantfile b/Vagrantfile
index 70a09581cedb4afbdc109b3b4013a1a3ef2227f0..5ac0c4b6a9bee7f9cdc30470134501691e15c3b6 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -32,6 +32,8 @@ SUPPORTED_OS = {
   "opensuse-tumbleweed" => {box: "opensuse/Tumbleweed.x86_64", user: "vagrant"},
   "oraclelinux"         => {box: "generic/oracle7",            user: "vagrant"},
   "oraclelinux8"        => {box: "generic/oracle8",            user: "vagrant"},
+  "rhel7"               => {box: "generic/rhel7",              user: "vagrant"},
+  "rhel8"               => {box: "generic/rhel8",              user: "vagrant"},
 }
 
 if File.exist?(CONFIG)
@@ -89,10 +91,10 @@ if ! File.exist?(File.join(File.dirname($inventory), "hosts.ini"))
 end
 
 if Vagrant.has_plugin?("vagrant-proxyconf")
-    $no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
-    (1..$num_instances).each do |i|
-        $no_proxy += ",#{$subnet}.#{i+100}"
-    end
+  $no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
+  (1..$num_instances).each do |i|
+      $no_proxy += ",#{$subnet}.#{i+100}"
+  end
 end
 
 Vagrant.configure("2") do |config|
@@ -177,9 +179,18 @@ Vagrant.configure("2") do |config|
         node.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true
       end
 
-      node.vm.synced_folder ".", "/vagrant", disabled: false, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z'] , rsync__exclude: ['.git','venv']
-      $shared_folders.each do |src, dst|
-        node.vm.synced_folder src, dst, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z']
+      if ["redhat7","redhat8"].include? $os
+        # Vagrant synced_folder rsync options cannot be used for RHEL boxes as Rsync package cannot
+        # be installed until the host is registered with a valid Red Hat support subscription
+        node.vm.synced_folder ".", "/vagrant", disabled: false
+        $shared_folders.each do |src, dst|
+          node.vm.synced_folder src, dst
+        end
+      else
+        node.vm.synced_folder ".", "/vagrant", disabled: false, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z'] , rsync__exclude: ['.git','venv']
+        $shared_folders.each do |src, dst|
+          node.vm.synced_folder src, dst, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z']
+        end
       end
 
       ip = "#{$subnet}.#{i+100}"
@@ -188,8 +199,8 @@ Vagrant.configure("2") do |config|
       # Disable swap for each vm
       node.vm.provision "shell", inline: "swapoff -a"
 
-      # Disable firewalld on oraclelinux vms
-      if ["oraclelinux","oraclelinux8"].include? $os
+      # Disable firewalld on oraclelinux/redhat vms
+      if ["oraclelinux","oraclelinux8","redhat7","redhat8"].include? $os
         node.vm.provision "shell", inline: "systemctl stop firewalld; systemctl disable firewalld"
       end
 
diff --git a/docs/centos8.md b/docs/centos8.md
index d22b8184ee0637cf86604b1be1ccb600f98ff315..8ddbe9e69935f01b8751588a7cb8b824be126e88 100644
--- a/docs/centos8.md
+++ b/docs/centos8.md
@@ -1,6 +1,6 @@
-# RHEL / CentOS 8
+# CentOS 8
 
-RHEL / CentOS 8 ships only with iptables-nft (ie without iptables-legacy)
+CentOS 8 ships only with iptables-nft (ie without iptables-legacy)
 The only tested configuration for now is using Calico CNI
 You need to use K8S 1.17+ and to add `calico_iptables_backend: "NFT"` to your configuration
 
diff --git a/docs/offline-environment.md b/docs/offline-environment.md
index 2d67df6dad6e805caf46eebf22c98b36f6fc4310..de8a9c8cb7bcf95a752ba7b817d66588077fa2ca 100644
--- a/docs/offline-environment.md
+++ b/docs/offline-environment.md
@@ -34,7 +34,7 @@ calicoctl_download_url: "{{ files_repo }}/kubernetes/calico/{{ calico_ctl_versio
 docker_rh_repo_base_url: "{{ yum_repo }}/docker-ce/$releasever/$basearch"
 docker_rh_repo_gpgkey: "{{ yum_repo }}/docker-ce/gpg"
 ## Containerd
-extras_rh_repo_base_url: "{{ yum_repo }}/centos/$releasever/extras/$basearch"
+extras_rh_repo_base_url: "{{ yum_repo }}/centos/{{ ansible_distribution_major_version }}/extras/$basearch"
 extras_rh_repo_gpgkey: "{{ yum_repo }}/containerd/gpg"
 
 # Fedora
diff --git a/docs/rhel.md b/docs/rhel.md
new file mode 100644
index 0000000000000000000000000000000000000000..b9f302e30b1ce0b6ca4c36152058526787daa6e4
--- /dev/null
+++ b/docs/rhel.md
@@ -0,0 +1,38 @@
+# Red Hat Enterprise Linux (RHEL)
+
+## RHEL Support Subscription Registration
+
+In order to install packages via yum or dnf, RHEL 7/8 hosts are required to be registered for a valid Red Hat support subscription.
+
+You can apply for a 1-year Development support subscription by creating a [Red Hat Developers](https://developers.redhat.com/) account. Be aware though that as the Red Hat Developers subscription is limited to only 1 year, it should not be used to register RHEL 7/8 hosts provisioned in Production environments.
+
+Once you have a Red Hat support account, simply add the credentials to the Ansible inventory parameters `rh_subscription_username` and `rh_subscription_password` prior to deploying Kubespray. If your company has a Corporate Red Hat support account, then obtain an **Organization ID** and **Activation Key**, and add these to the Ansible inventory parameters `rh_subscription_org_id` and `rh_subscription_activation_key` instead of using your Red Hat support account credentials.
+
+```ini
+rh_subscription_username: ""
+rh_subscription_password: ""
+# rh_subscription_org_id: ""
+# rh_subscription_activation_key: ""
+```
+
+Either the Red Hat support account username/password, or Organization ID/Activation Key combination must be specified in the Ansible inventory in order for the Red Hat subscription registration to complete successfully during the deployment of Kubespray.
+
+Update the Ansible inventory parameters `rh_subscription_usage`, `rh_subscription_role` and `rh_subscription_sla` if necessary to suit your specific requirements.
+
+```ini
+rh_subscription_usage: "Development"
+rh_subscription_role: "Red Hat Enterprise Server"
+rh_subscription_sla: "Self-Support"
+```
+
+If the RHEL 7/8 hosts are already registered to a valid Red Hat support subscription via an alternative configuration management approach prior to the deployment of Kubespray, the successful RHEL `subscription-manager` status check will simply result in the RHEL subscription registration tasks being skipped.
+
+## RHEL 8
+
+RHEL 8 ships only with iptables-nft (ie without iptables-legacy)
+The only tested configuration for now is using Calico CNI
+You need to use K8S 1.17+ and to add `calico_iptables_backend: "NFT"` to your configuration
+
+If you have containers that are using iptables in the host network namespace (`hostNetwork=true`),
+you need to ensure they are using iptables-nft.
+An example how k8s do the autodetection can be found [in this PR](https://github.com/kubernetes/kubernetes/pull/82966)
diff --git a/inventory/sample/group_vars/all/all.yml b/inventory/sample/group_vars/all/all.yml
index 4ddc54ab3fedc2a57014851fac2048e30ead2c4e..2c24e92f4308a917b16b9d12092a68761c4b86da 100644
--- a/inventory/sample/group_vars/all/all.yml
+++ b/inventory/sample/group_vars/all/all.yml
@@ -97,3 +97,14 @@ no_proxy_exclude_workers: false
 ## Deploy container engine
 # Set false if you want to deploy container engine manually.
 # deploy_container_engine: true
+
+## Red Hat Enterprise Linux subscription registration
+## Add either RHEL subscription Username/Password or Organization ID/Activation Key combination
+## Update RHEL subscription purpose usage, role and SLA if necessary
+# rh_subscription_username: ""
+# rh_subscription_password: ""
+# rh_subscription_org_id: ""
+# rh_subscription_activation_key: ""
+# rh_subscription_usage: "Development"
+# rh_subscription_role: "Red Hat Enterprise Server"
+# rh_subscription_sla: "Self-Support"
diff --git a/roles/bootstrap-os/handlers/main.yml b/roles/bootstrap-os/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7c8c4fef70666701f08983369264ed19f632389d
--- /dev/null
+++ b/roles/bootstrap-os/handlers/main.yml
@@ -0,0 +1,4 @@
+---
+- name: RHEL auto-attach subscription
+  command: /sbin/subscription-manager attach --auto
+  become: true
diff --git a/roles/bootstrap-os/tasks/bootstrap-redhat.yml b/roles/bootstrap-os/tasks/bootstrap-redhat.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f2518557bfb57a8d70a901eedf375df639178023
--- /dev/null
+++ b/roles/bootstrap-os/tasks/bootstrap-redhat.yml
@@ -0,0 +1,85 @@
+---
+- name: Gather host facts to get ansible_distribution_version ansible_distribution_major_version
+  setup:
+    gather_subset: '!all'
+    filter: ansible_distribution_*version
+
+- name: Check RHEL subscription-manager status
+  command: /sbin/subscription-manager status
+  register: rh_subscription_status
+  changed_when: "rh_subscription_status != 0"
+  ignore_errors: true
+  become: true
+
+- name: RHEL subscription Organization ID/Activation Key registration
+  redhat_subscription:
+    state: present
+    org_id: "{{ rh_subscription_org_id }}"
+    activationkey: "{{ rh_subscription_activation_key }}"
+    auto_attach: true
+    force_register: true
+    syspurpose:
+      usage: "{{ rh_subscription_usage }}"
+      role: "{{ rh_subscription_role }}"
+      service_level_agreement: "{{ rh_subscription_sla }}"
+      sync: true
+  notify: RHEL auto-attach subscription
+  ignore_errors: true
+  become: true
+  when:
+    - rh_subscription_org_id is defined
+    - rh_subscription_status.changed
+
+- name: RHEL subscription Username/Password registration
+  redhat_subscription:
+    state: present
+    username: "{{ rh_subscription_username }}"
+    password: "{{ rh_subscription_password }}"
+    auto_attach: true
+    force_register: true
+    syspurpose:
+      usage: "{{ rh_subscription_usage }}"
+      role: "{{ rh_subscription_role }}"
+      service_level_agreement: "{{ rh_subscription_sla }}"
+      sync: true
+  notify: RHEL auto-attach subscription
+  ignore_errors: true
+  become: true
+  when:
+    - rh_subscription_username is defined
+    - rh_subscription_status.changed
+
+- name: Check presence of fastestmirror.conf
+  stat:
+    path: /etc/yum/pluginconf.d/fastestmirror.conf
+  register: fastestmirror
+
+# the fastestmirror plugin can actually slow down Ansible deployments
+- name: Disable fastestmirror plugin if requested
+  lineinfile:
+    dest: /etc/yum/pluginconf.d/fastestmirror.conf
+    regexp: "^enabled=.*"
+    line: "enabled=0"
+    state: present
+  become: true
+  when:
+    - fastestmirror.stat.exists
+    - not centos_fastestmirror_enabled
+
+- name: Add proxy to /etc/yum.conf if http_proxy is defined
+  ini_file:
+    path: "/etc/yum.conf"
+    section: main
+    option: proxy
+    value: "{{ http_proxy | default(omit) }}"
+    state: "{{ http_proxy | default(False) | ternary('present', 'absent') }}"
+    no_extra_spaces: true
+  become: true
+
+# libselinux-python is required on SELinux enabled hosts
+# See https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#managed-node-requirements
+- name: Install libselinux python package
+  package:
+    name: "{{ ( (ansible_distribution_major_version | int) < 8) | ternary('libselinux-python','python3-libselinux') }}"
+    state: present
+  become: true
diff --git a/roles/bootstrap-os/tasks/main.yml b/roles/bootstrap-os/tasks/main.yml
index 2047c5f4a9eb89f951e774e9d350f9842e302a56..4df0b1944726d025f3c19645fcf75cfc17f555c3 100644
--- a/roles/bootstrap-os/tasks/main.yml
+++ b/roles/bootstrap-os/tasks/main.yml
@@ -8,7 +8,10 @@
   environment: {}
 
 - include_tasks: bootstrap-centos.yml
-  when: '"CentOS" in os_release.stdout or "Red Hat Enterprise Linux" in os_release.stdout or "Oracle" in os_release.stdout'
+  when: '"CentOS" in os_release.stdout or "Oracle" in os_release.stdout'
+
+- include_tasks: bootstrap-redhat.yml
+  when: '"Red Hat Enterprise Linux" in os_release.stdout'
 
 - include_tasks: bootstrap-clearlinux.yml
   when: '"Clear Linux OS" in os_release.stdout'
diff --git a/roles/container-engine/containerd/defaults/main.yml b/roles/container-engine/containerd/defaults/main.yml
index 222cf5bfac7dea02a19ce627541bd75e376a9836..bac182fc04d29a828bbf03e23a26bb4d17bc271d 100644
--- a/roles/container-engine/containerd/defaults/main.yml
+++ b/roles/container-engine/containerd/defaults/main.yml
@@ -32,7 +32,7 @@ containerd_repo_info:
   repos:
 
 extras_rh_repo_base_url: "http://mirror.centos.org/centos/{{ ansible_distribution_major_version }}/extras/$basearch/"
-extras_rh_repo_gpgkey: "http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-{{ ansible_distribution_major_version }}"
+extras_rh_repo_gpgkey: "http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-7"
 
 # Ubuntu docker-ce repo
 containerd_ubuntu_repo_base_url: "https://download.docker.com/linux/ubuntu"
diff --git a/roles/container-engine/containerd/tasks/containerd_repo.yml b/roles/container-engine/containerd/tasks/containerd_repo.yml
index c141bfc4aa605750ed62b35bf7c917b29a14a58c..5614b06d725db5a082de8225ff692c82513439c8 100644
--- a/roles/container-engine/containerd/tasks/containerd_repo.yml
+++ b/roles/container-engine/containerd/tasks/containerd_repo.yml
@@ -54,7 +54,7 @@
 - name: Configure extras repository on RedHat/CentOS if container-selinux is not available in current repos
   yum_repository:
     name: extras
-    description: "CentOS-7 - Extras"
+    description: "CentOS-{{ ansible_distribution_major_version }} - Extras"
     state: present
     baseurl: "{{ extras_rh_repo_base_url }}"
     file: "extras"
diff --git a/roles/container-engine/docker/defaults/main.yml b/roles/container-engine/docker/defaults/main.yml
index b80efe5e9b383be07167719318891be2aac3b334..616ddadd4c9c8daa3964febc4f69ba7c624ea234 100644
--- a/roles/container-engine/docker/defaults/main.yml
+++ b/roles/container-engine/docker/defaults/main.yml
@@ -44,7 +44,7 @@ docker_debian_repo_gpgkey: 'https://download.docker.com/linux/debian/gpg'
 docker_bin_dir: "/usr/bin"
 # CentOS/RedHat Extras repo
 extras_rh_repo_base_url: "http://mirror.centos.org/centos/{{ ansible_distribution_major_version }}/extras/$basearch/"
-extras_rh_repo_gpgkey: "http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-{{ ansible_distribution_major_version }}"
+extras_rh_repo_gpgkey: "http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-7"
 
 # flag to enable/disable docker cleanup
 docker_orphan_clean_up: false
diff --git a/roles/container-engine/docker/tasks/main.yml b/roles/container-engine/docker/tasks/main.yml
index 7e610369d1ef3d39262eaaa40a48bc877d4f8267..d6bc6f555137188a6af0e9797b12c100debe8953 100644
--- a/roles/container-engine/docker/tasks/main.yml
+++ b/roles/container-engine/docker/tasks/main.yml
@@ -130,7 +130,7 @@
 - name: Configure extras repository on RedHat/CentOS if container-selinux is not available in current repos
   yum_repository:
     name: extras
-    description: "CentOS-7 - Extras"
+    description: "CentOS-{{ ansible_distribution_major_version }} - Extras"
     state: present
     baseurl: "{{ extras_rh_repo_base_url }}"
     file: "extras"
diff --git a/roles/container-engine/docker/vars/redhat.yml b/roles/container-engine/docker/vars/redhat.yml
index 397916c0b00930c28a88e04e568e87b126044a83..960cf49dd92846bf9175cad9144246e9738c5b14 100644
--- a/roles/container-engine/docker/vars/redhat.yml
+++ b/roles/container-engine/docker/vars/redhat.yml
@@ -27,7 +27,6 @@ docker_selinux_versioned_pkg:
   'stable': docker-ce-selinux-17.03.3.ce-1.el7
   'edge': docker-ce-selinux-17.03.3.ce-1.el7
 
-
 docker_pkgs_use_docker_ce:
   - name: "{{ docker_selinux_versioned_pkg[docker_selinux_version | string] }}"
     yum_conf: "{{ docker_yum_conf }}"