diff --git a/doc/requirements.txt b/doc/requirements.txt
index f28680cd5..9227414ca 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -4,6 +4,5 @@
 
 openstackdocstheme>=1.19.0 # Apache-2.0
 reno!=2.3.1,>=1.8.0 # Apache-2.0
-sphinx>=1.8.0,<2.0.0;python_version=='2.7' # BSD
 sphinx>=1.8.0,!=2.1.0;python_version>='3.4' # BSD
 sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
diff --git a/releasenotes/notes/drop-py-2-7-3d0a7f3eb8f11d6b.yaml b/releasenotes/notes/drop-py-2-7-3d0a7f3eb8f11d6b.yaml
new file mode 100644
index 000000000..744bc8a82
--- /dev/null
+++ b/releasenotes/notes/drop-py-2-7-3d0a7f3eb8f11d6b.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - |
+    Python 2.7 support has been dropped. Last release of kayobe
+    to support py2.7 is OpenStack Train. The minimum version of Python now
+    supported by kayobe is Python 3.6.
diff --git a/setup.cfg b/setup.cfg
index 377ebfdaf..3092250b8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -13,10 +13,9 @@ classifier =
     License :: OSI Approved :: Apache Software License
     Operating System :: POSIX :: Linux
     Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.5
+    Programming Language :: Python :: 3.6
+    Programming Language :: Python :: 3.7
 
 # In below section we have to include the roles directory explicitly
 # to Workaround PBR bug:
diff --git a/tox.ini b/tox.ini
index 77bf17702..c83668eda 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,9 +1,10 @@
 [tox]
 minversion = 2.0
-envlist = py3,py27,pep8
+envlist = py3,pep8
 skipsdist = True
 
 [testenv]
+basepython = python3
 usedevelop = True
 install_command = pip install {opts} {packages}
 passenv =
@@ -24,7 +25,6 @@ deps =
 commands = stestr run {posargs}
 
 [testenv:pep8]
-basepython = python3
 # sphinx8 needs the sphinx package which is required via doc/requirements.txt
 deps =
     -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train}
@@ -41,7 +41,6 @@ commands =
   yamllint etc/kayobe
 
 [testenv:venv]
-basepython = python3
 deps =
     -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train}
     -r{toxinidir}/test-requirements.txt
@@ -49,7 +48,8 @@ deps =
 commands = {posargs}
 
 [testenv:ansible]
-# Kolla currently fails during password generation under python3. Revisit in Rocky.
+# FIXME(mgoddard): Ansible playbooks do not yet support Python 3, so we need to run these
+# tests using Python 2 for the time being.
 basepython = python2
 usedevelop = True
 # Create the virtualenv with access to system site packages, as this is
@@ -63,8 +63,6 @@ commands =
     {toxinidir}/tools/test-ansible.sh {posargs}
 
 [testenv:molecule]
-# Molecule only supports python 2.7 and 3.6.
-basepython = python2
 deps =
     -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train}
     -r{toxinidir}/test-requirements.txt
@@ -79,11 +77,9 @@ commands =
     bash -c "source {envdir}/bin/activate && {toxinidir}/tools/test-molecule.sh {posargs}"
 
 [testenv:alint]
-basepython = python3
 commands = ansible-lint ansible/*.yaml
 
 [testenv:ansible-syntax]
-basepython = python3
 commands =
     # Install ansible role dependencies from Galaxy.
     {toxinidir}/tools/ansible-galaxy-retried.sh install \
@@ -104,7 +100,6 @@ commands =
         {posargs}"
 
 [testenv:cover]
-basepython = python3
 setenv =
     VIRTUAL_ENV={envdir}
     PYTHON=coverage run --source kayobe --parallel-mode
@@ -117,7 +112,6 @@ commands =
     coverage xml -o cover/coverage.xml
 
 [testenv:docs]
-basepython = python3
 deps =
     -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train}
     -r{toxinidir}/requirements.txt
@@ -127,7 +121,6 @@ commands =
   sphinx-build -W --keep-going -b html doc/source doc/build/html
 
 [testenv:pdf-docs]
-basepython = python3
 whitelist_externals = make
 deps = {[testenv:docs]deps}
 commands =
@@ -136,11 +129,9 @@ commands =
   make -C doc/build/pdf
 
 [testenv:debug]
-basepython = python3
 commands = oslo_debug_helper {posargs}
 
 [testenv:releasenotes]
-basepython = python3
 deps =
     -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/train}
     -r{toxinidir}/requirements.txt
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index af5d87b12..bea8e5e0e 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -19,6 +19,10 @@
     parent: openstack-tox-with-sudo
     vars:
       tox_envlist: ansible
+    required-projects:
+      - name: openstack/requirements
+        # TODO(mgoddard): Remove when Ansible playbooks support Python 3.
+        override-checkout: stable/train
     irrelevant-files:
       - ^.*\.rst$
       - ^doc/.*
@@ -54,13 +58,13 @@
       - name: openstack/kayobe
       - name: openstack/kayobe-config-dev
       - name: openstack/kolla
-        # TODO(wszumski): Remove when kayobe stable/train exists.
+        # TODO(mgoddard): Remove when Ansible playbooks support Python 3.
         override-checkout: stable/train
       - name: openstack/kolla-ansible
-        # TODO(wszumski): Remove when kayobe stable/train exists.
+        # TODO(mgoddard): Remove when Ansible playbooks support Python 3.
         override-checkout: stable/train
       - name: openstack/requirements
-        # TODO(wszumski): Remove when kayobe stable/train exists.
+        # TODO(mgoddard): Remove when Ansible playbooks support Python 3.
         override-checkout: stable/train
       - name: openstack/tenks
     irrelevant-files:
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 3a6d98baf..74d01e5de 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -2,9 +2,7 @@
 - project:
     templates:
       - openstack-cover-jobs
-      - openstack-python35-jobs
-      - openstack-python36-jobs
-      - openstack-python-jobs
+      - openstack-python3-ussuri-jobs
       - publish-openstack-docs-pti
       - release-notes-jobs-python3
     check: