diff --git a/cluster.yml b/cluster.yml
index f77b4595148b5f6794166776f7d76dfe0761acd7..e773931bf421b248186c85c77eac5a2a18eed400 100644
--- a/cluster.yml
+++ b/cluster.yml
@@ -26,6 +26,7 @@
 - hosts: k8s-cluster:etcd:calico-rr
   any_errors_fatal: true
   roles:
+    - { role: kernel-upgrade, tags: kernel-upgrade, when: kernel_upgrade is defined and kernel_upgrade }
     - { role: kubernetes/preinstall, tags: preinstall }
     - { role: docker, tags: docker }
     - role: rkt
diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml
index 88a357a8263435d3ede220081c213acc0a904f06..d04b7c95c63003154c56a0651d604470de911bbf 100644
--- a/inventory/group_vars/all.yml
+++ b/inventory/group_vars/all.yml
@@ -222,3 +222,6 @@ efk_enabled: false
 ## cluster of Hashicorp's Vault is started to issue certificates (using etcd
 ## as a backend). Options are "script" or "vault"
 cert_management: script
+
+# Please specify true if you want to perform a kernel upgrade
+kernel_upgrade: false
diff --git a/roles/kernel-upgrade/defaults/main.yml b/roles/kernel-upgrade/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..51ebd68ffca607969ce6def0e1f73f4231b2e644
--- /dev/null
+++ b/roles/kernel-upgrade/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+
+elrepo_key_url: 'https://www.elrepo.org/RPM-GPG-KEY-elrepo.org'
+elrepo_rpm : elrepo-release-7.0-2.el7.elrepo.noarch.rpm
+elrepo_mirror : http://www.elrepo.org
+
+elrepo_url : '{{elrepo_mirror}}/{{elrepo_rpm}}'
+
+elrepo_kernel_package: "kernel-lt"
diff --git a/roles/kernel-upgrade/tasks/centos-7.yml b/roles/kernel-upgrade/tasks/centos-7.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3181c2132de069ad7d21baeebaaf5c04d6d9937
--- /dev/null
+++ b/roles/kernel-upgrade/tasks/centos-7.yml
@@ -0,0 +1,28 @@
+---
+
+- name: install ELRepo key
+  rpm_key: state=present key='{{ elrepo_key_url }}'
+
+- name: install elrepo repository
+  yum:
+    name: '{{elrepo_url}}'
+    state: present
+
+- name: upgrade kernel
+  yum: name={{elrepo_kernel_package}} state=present enablerepo=elrepo-kernel
+  register: upgrade
+
+- name: change default grub entry
+  lineinfile:
+    dest: '/etc/default/grub'
+    regexp: '^GRUB_DEFAULT=.*'
+    line: 'GRUB_DEFAULT=0'
+  when: upgrade.changed
+  register: grub_entry
+
+- name: re-generate grub-config
+  command: grub2-mkconfig -o /boot/grub2/grub.cfg
+  when: upgrade.changed and grub_entry.changed
+
+- include: reboot.yml
+  when: upgrade.changed
\ No newline at end of file
diff --git a/roles/kernel-upgrade/tasks/main.yml b/roles/kernel-upgrade/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..999eb94aeb6abcb68f50c30329b81b650aa3e195
--- /dev/null
+++ b/roles/kernel-upgrade/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+
+- include: centos-7.yml
+  when: ansible_distribution in ["CentOS","RedHat"] and
+        ansible_distribution_major_version >= 7
diff --git a/roles/kernel-upgrade/tasks/reboot.yml b/roles/kernel-upgrade/tasks/reboot.yml
new file mode 100644
index 0000000000000000000000000000000000000000..51c3833868b04fe12ead626d0886cff6c1a51216
--- /dev/null
+++ b/roles/kernel-upgrade/tasks/reboot.yml
@@ -0,0 +1,30 @@
+---
+
+# Reboot the machine gets more complicated as we want to support bastion hosts. A simple wait_for task would not work
+# as we can not directly reach the hosts (except the bastion). In case a basion is used, we first check for it to come
+# back. After it is back, we check for all the hosts by delegating to the bastion.
+
+- name: Rebooting server
+  shell: nohup bash -c "sleep 5 && shutdown -r now 'Reboot required for updated kernel'" &
+
+- name: Wait for some seconds
+  pause: seconds=10
+
+- set_fact:
+    is_bastion: "{{ inventory_hostname == 'bastion' }}"
+    wait_for_delegate: "localhost"
+- set_fact:
+    wait_for_delegate: "{{hostvars['bastion']['ansible_ssh_host']}}"
+  when: "{{ 'bastion' in groups['all'] }}"
+
+- name: wait for bastion to come back
+  wait_for: host={{ ansible_ssh_host }} port=22 delay=10 timeout=300
+  become: false
+  delegate_to: localhost
+  when: "is_bastion"
+
+- name: waiting for server to come back (using bastion if necessary)
+  wait_for: host={{ ansible_ssh_host }} port=22 delay=10 timeout=300
+  become: false
+  delegate_to: "{{ wait_for_delegate }}"
+  when: "not is_bastion"