diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6a66ba011918731d809c0b7f74258cd49703b16a..dce5200f1c365c5d0cd773d94efbb851218a1a54 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -69,15 +69,13 @@ stages:
 .setup_git:
   image: bitnami/git
   before_script:
+    # Use a token that has git push permissions. Token must be created in the
+    # GitLab GUI; a project variable must be created containing the token.
+    # See file `DEVELOPER.md` for details.
     - !reference [.release, before_script]
-    - eval $(ssh-agent -s)
-    - chmod 400 $SSH_PRIVATE_KEY
-    - ssh-add $SSH_PRIVATE_KEY
-    - mkdir -p ~/.ssh
-    - ssh-keyscan $CI_SERVER_HOST > ~/.ssh/known_hosts
     - git config user.email $GITLAB_USER_EMAIL
     - git config user.name $GITLAB_USER_NAME
-    - git remote set-url origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
+    - git remote set-url origin https://oauth2:$GIT_PUSH_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git
 
 .setup_docker:
   stage: build
@@ -149,7 +147,7 @@ prepare_release:
     # Use .versioning:script to get LINC_TAG
     - !reference [.versioning, script]
     - echo "Updating dockerPull URI to use image tag '$LINC_TAG'"
-    - sed -ri "/dockerPull/s,(astronrd/linc).*,\1:$LINC_TAG," steps/*.cwl
+    - sed -ri "/dockerPull/s,['\"]?(astronrd/linc).*,\1:$LINC_TAG," steps/*.cwl
     - git add -u steps/*.cwl
     # Only commit if there are changes
     - |
diff --git a/DEVELOPER.md b/DEVELOPER.md
index d35df8ff73b2b526303f4a5eb14c8846486b2f68..f5f66502a5d6fabf7fda99dfe3573696b7d02834 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -2,7 +2,16 @@
 
 ## Creating a release
 
-Creating a LINC release is a bit more involved than simply pressing a button in the GitLab GUI. The main reason is that all the CWL files that contain a `dockerPull` line need to be updated on-the-fly to contain the proper reference to the release. This is taken care of by the CI/CD pipeline, but it is good to understand how this pipeline works under the hood.
+Creating a LINC release is a bit more involved than simply pressing a button in the GitLab GUI. The main reason is that all the CWL files that contain a `dockerPull` line need to be updated on-the-fly to contain the proper reference to the release. This is taken care of by the CI/CD pipeline, but it is good to understand how this pipeline works under the hood. First, let's properly configure the GitLab project.
+
+### Configure the project in the GitLab GUI
+
+The CI/CD pipelines needs to have push rights to the Git repository. We use an access token to grant these rights. The following preparations need to be done only once (though they have to be repeated when the access token expires):
+
+- Create a project access token (`Settings > Access tokens`), and grant it the `Maintainer` role and the `write_repository` scope. Copy the token directly after you've created it, because there is no way to retrieve it later on.
+- Create a project variable (`Settings > CI/CD > Variables`) named `GIT_PUSH_TOKEN`, and set its value to the access token that you just created (and copied!). Mark the variable as masked and protected. This variable will be used when a release is created (see `.gitlab-ci.yml` file).
+
+**NOTE**: The name of the access token will be used in the `Created by` column in the `Pipelines` view for pipelines that were triggered as a result of an automatic `git push` action.
 
 ### What does the CI/CD pipeline consider a release?