diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8875166f3c8d77cf71e6128cb99a0b04b6f6d4ae..eda55815c0b90a36b3d2cd3698ede1c48955d4cc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,19 +1,21 @@
-# Note: there's no job to lint the .yml files, because:
-#
-# - The GitLab API for linting does not support local includes
-#   and .extends is not fully supported [1].
-# - Local linting with e.g. check-jsonschema [2]
-#   does not support GitLab's custom !reference tag [3] [4].
-#
-# [1] https://docs.gitlab.com/ee/api/lint.html#yaml-expansion
-# [2] https://github.com/python-jsonschema/check-jsonschema
-# [3] https://gitlab.com/gitlab-org/gitlab/-/issues/348666#note_804097628
-# [4] https://github.com/SchemaStore/schemastore/issues/1476
-
 include:
   - local: '/templates/shared/all.yml'
   - local: '/templates/changedfiles/all.yml'
 
+lint:
+  stage: lint
+  # Note: the ci-tools image has to be build and pushed manually once to bootstrap this job
+  # since this job comes before the build_containers job.
+  image: ${CI_REGISTRY_IMAGE}/ci-tools:master
+  rules:
+    - !reference [.primary_ref_jobs, rules]
+    - !reference [.merge_request_jobs, rules]
+  script:
+    # Note: we cannot use the GitLab API https://docs.gitlab.com/ee/api/lint.html
+    # for this since that does not support local includes.
+    - shopt -s globstar dotglob
+    - check-jsonschema --data-transform gitlab-ci --builtin-schema vendor.gitlab-ci **/*.yml
+
 build_containers:
   stage: build
   image:
diff --git a/dockerfiles/ci-tools/Dockerfile b/dockerfiles/ci-tools/Dockerfile
index d1b2b49ff55a39716a70befde1a23a1bd421eb0c..489159f6cd61a6cb97ff9c4cb0a50aa74d27e4d7 100644
--- a/dockerfiles/ci-tools/Dockerfile
+++ b/dockerfiles/ci-tools/Dockerfile
@@ -15,6 +15,7 @@ RUN apt-get update && apt-get -y install \
 RUN pip install \
     black==22.3.0 \
     autopep8 \
+    check-jsonschema \
     python-gitlab \
     python-compare-ast \
     coverage-fixpaths \
diff --git a/dockerfiles/ci-tools/README.rst b/dockerfiles/ci-tools/README.rst
index ef44f0fd5669532690a5b6c11aab7d761661d69c..13b59122f17be701bb04214bbd94972360aea4f5 100644
--- a/dockerfiles/ci-tools/README.rst
+++ b/dockerfiles/ci-tools/README.rst
@@ -18,6 +18,7 @@ List of tools installed:
 * `autopep8`_
 * `release-cli`_
 * `python-gitlab`_
+* `check-jsonschema`_
 * `junitparser`_
 * `anybadge`_
 * `python-compare-ast`_
@@ -83,3 +84,4 @@ Usage:
 .. _python-compare-ast: https://github.com/omegacen/python-compare-ast
 .. _coverage-fixpaths: https://github.com/omegacen/coverage-fixpaths
 .. _git-scripts: https://gitlab.astro-wise.org/omegacen/git-scripts
+.. _check-jsonschema: https://github.com/python-jsonschema/check-jsonschema