diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index db3c554e8fda79601c6e46b2d96c8866947ddbd0..ca17c8fb0bc3818b98e2f2e3cdfeb504f187a984 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,6 +12,12 @@ variables:
   JOB: check
   PYTHONUNBUFFERED: 1
   SENSITIVE: 1
+  TF_HTTP_LOCK_METHOD: POST
+  TF_HTTP_PASSWORD: ${CI_JOB_TOKEN}
+  TF_HTTP_RETRY_WAIT_MIN: 5
+  TF_HTTP_UNLOCK_METHOD: DELETE
+  TF_HTTP_USERNAME: gitlab-ci-token
+  TF_IN_AUTOMATION: 'true'
 
 flake8:
   stage: build
@@ -20,14 +26,20 @@ flake8:
   rules:
     - if: '$JOB =~ /all|check/'
 
-terraform-single:
+test-single:
   stage: test
+  variables: &tfvars
+    TF_HTTP_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_JOB_NAME}
+    TF_HTTP_LOCK_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_JOB_NAME}/lock
+    TF_HTTP_UNLOCK_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_JOB_NAME}/lock
   before_script: &before
     - sudo apt-get update
     - sudo apt-get install -y --no-install-recommends git
-    - rm -fv clouds.yaml testsuite.auto.tfvars
+    - rm -fv clouds.yaml testsuite.auto.tfvars gitlab.tf
     - ln -sfv $CLOUDS_YAML clouds.yaml
     - ln -sfv $TERRAFORM_CONFIG testsuite.auto.tfvars
+    # GitLab remote terraform state
+    - printf 'terraform {\n  backend "http" {\n  }\n}\n' > gitlab.tf
     # https://github.com/terraform-provider-openstack/terraform-provider-openstack/issues/1160
     - touch ./secure.yml
     - ip=`openstack floating ip create -c floating_ip_address -f value public-muni-147-251-21-GROUP`
@@ -36,9 +48,8 @@ terraform-single:
     key: single
     paths:
       - ".terraform/"
-      - "*.tfstate"
   script:
-    - terraform init
+    - terraform init -input=false
     - args="-auto-approve -var type=hadoop-single -var flavor=standard.large -var n=0 -var domain=terra1 -var image_name=$IMAGE_NAME -var image_visibility=$IMAGE_VISIBILITY -var floating_ip=$ip"
     - terraform apply $args
     - eval $(ssh-agent -s)
@@ -52,17 +63,17 @@ terraform-single:
     paths:
       - "*.log"
 
-terraform-cluster:
+test-cluster:
   stage: test
+  variables: *tfvars
   before_script: *before
   cache:
     when: always
     key: cluster
     paths:
       - ".terraform/"
-      - "*.tfstate"
   script:
-    - terraform init
+    - terraform init -input=false
     - args="-auto-approve -var type=hadoop -var domain=terra2 -var image_name=$IMAGE_NAME -var image_visibility=$IMAGE_VISIBILITY -var floating_ip=$ip"
     - terraform apply $args
     - eval $(ssh-agent -s)