diff --git a/.gitignore b/.gitignore
index 3377d94390180530dfaa2f15939b6f2ede90f68d..387cc3095f6697c7175df47c85169052726ca547 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,4 @@ reports/
 Ansible/*.crt
 Ansible/*.csr
 Ansible/*.key
+Ansible/collections
diff --git a/Ansible/ansible.cfg b/Ansible/ansible.cfg
index 45588da8bc3c425823f710a6751b49a02b148aba..1c8279076de7298ff412fadb5dda6b5d0b8fd145 100644
--- a/Ansible/ansible.cfg
+++ b/Ansible/ansible.cfg
@@ -1,5 +1,6 @@
 [defaults]
 callback_enabled = ansible.posix.profile_tasks, ansible.posix.timer
+collections_path = {{CWD}}/collections
 deprecation_warnings = True
 fact_caching = jsonfile
 fact_caching_connection = ~/.ansible/facts
diff --git a/Ansible/collections/.gitkeep b/Ansible/collections/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Ansible/project_ci_aws_creds.yaml b/Ansible/project_ci_aws_creds.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8c52376d5051806fd92f01105d7a112c302b9b84
--- /dev/null
+++ b/Ansible/project_ci_aws_creds.yaml
@@ -0,0 +1,208 @@
+---
+- name: Generate AWS credentials for a GitLab project CI
+  hosts: localhost
+  gather_facts: false
+  become: false
+  vars_prompt:
+    - name: project_full_name
+      # yamllint disable-line rule:line-length
+      prompt: Full name for the GitLab project (namespace included, eg. group/project)
+      private: false
+    - name: aws_region
+      prompt: List of AWS regions to limit the IAM user (comma separated)
+      default: us-east-1
+      private: false
+  vars:
+    aws_username: "{{ project_name }}-ci"
+    aws_limit_policy:
+      Statement:
+        - Sid: LimitIP
+          Effect: Deny
+          Action: "*"
+          Resource: "*"
+          Condition:
+            ForAnyValue:NotIpAddress:
+              aws:SourceIp: '{{ shore_ip_addresses }}'
+        - Sid: LimitRegion
+          Effect: Deny
+          NotAction:
+            - cloudfront:*
+            - iam:*
+            - route53:*
+            - support:*
+          Resource: "*"
+          Condition:
+            ForAnyValue:StringNotEqualsIfExists:
+              aws:RequestedRegion: '{{ aws_region.split(",") }}'
+    aws_resourcegroup_policy:
+      Version: 2012-10-17
+      Statement:
+        - Sid: ResourceGroupFullAccess
+          Effect: Allow
+          Action: "resource-groups:*"
+          Resource: "*"
+    gitlab_base_url: "{{ lookup('env', 'GITLAB_BASE_URL') }}"
+    gitlab_token: "{{ lookup('env', 'GITLAB_TOKEN') }}"
+    project_id: '{{ project_dict["id"] }}'
+    project_name: '{{ project_dict["path"] }}'
+    shore_ip_addresses:
+      - "{{ lookup('community.general.dig', 'ns1.shore.co.il') }}"
+      - "{{ lookup('community.general.dig', 'ns4.shore.co.il') }}"
+  tasks:
+    - name: Search for GitLab projects with the same name
+      ansible.builtin.uri:
+        headers: &gitlab_headers
+          Authorization: Bearer {{ gitlab_token }}
+        method: GET
+        # yamllint disable-line rule:line-length
+        url: "{{ gitlab_base_url }}/search?scope=projects&search={{ project_full_name.split('/')[1] }}"
+      register: search_projects
+
+    - name: Find the right GitLab project
+      ansible.builtin.set_fact:
+        project_dict: >-
+          {{
+            search_projects.json|
+            selectattr("path_with_namespace", "equalto", project_full_name)|
+            first
+          }}
+
+    - name: Create a full access resource group IAM policy
+      community.aws.iam_managed_policy:
+        policy: '{{ aws_resourcegroup_policy|to_json }}'
+        policy_description: Provides full access to AWS Resource Groups
+        policy_name: &rg_policy_name AWSResourceGroupsFullAccess
+        state: present
+
+    - name: Create the IAM user
+      community.aws.iam_user:
+        managed_policies:
+          - *rg_policy_name
+        name: "{{ aws_username }}"
+        purge_policies: false
+        state: present
+        tags:
+          Project: '{{ project_name }}'
+
+    - name: Attach an inline policy to limit the IAM user
+      community.aws.iam_policy:
+        iam_name: '{{ aws_username }}'
+        iam_type: user
+        policy_json: '{{ aws_limit_policy|to_json }}'
+        policy_name: '{{ aws_username }}-limit'
+        skip_duplicates: true
+        state: present
+
+    # yamllint disable-line rule:line-length
+    - name: Create access key for the IAM user (a new one every time, task will always change)
+      community.aws.iam_access_key:
+        active: true
+        rotate_keys: true
+        state: present
+        user_name: '{{ aws_username }}'
+      register: aws_access_key
+
+    - name: Get the GitLab project CI variables
+      ansible.builtin.uri:
+        headers: *gitlab_headers
+        method: GET
+        url: "{{ gitlab_base_url }}/projects/{{ project_id }}/variables"
+      changed_when: false
+      register: project_vars
+
+    - name: Create the access key ID GitLab CI variable
+      # yamllint disable-line rule:line-length
+      when: project_vars.json|selectattr("key", "equalto", "AWS_ACCESS_KEY_ID")|length == 0
+      ansible.builtin.uri:
+        body:
+          environment_scope: "*"
+          key: AWS_ACCESS_KEY_ID
+          masked: false
+          protected: false
+          value: '{{ aws_access_key.access_key_id }}'
+          variable_key: env_var
+        body_format: form-urlencoded
+        headers: *gitlab_headers
+        method: POST
+        status_code: 201
+        url: "{{ gitlab_base_url }}/projects/{{ project_id }}/variables"
+
+    - name: Update the access key ID GitLab CI variable (will always change)
+      # yamllint disable-line rule:line-length
+      when: project_vars.json|selectattr("key", "equalto", "AWS_ACCESS_KEY_ID")|length == 1
+      changed_when: true
+      ansible.builtin.uri:
+        body:
+          environment_scope: "*"
+          masked: false
+          protected: false
+          value: '{{ aws_access_key.access_key_id }}'
+          variable_key: env_var
+        body_format: form-urlencoded
+        headers: *gitlab_headers
+        method: PUT
+        status_code: 200
+        # yamllint disable-line rule:line-length
+        url: "{{ gitlab_base_url }}/projects/{{ project_id }}/variables/AWS_ACCESS_KEY_ID"
+
+    - name: Create the secret access key GitLab CI variable
+      # yamllint disable-line rule:line-length
+      when: project_vars.json|selectattr("key", "equalto", "AWS_SECRET_ACCESS_KEY")|length == 0
+      ansible.builtin.uri:
+        body:
+          environment_scope: "*"
+          key: AWS_SECRET_ACCESS_KEY
+          masked: true
+          protected: false
+          value: '{{ aws_access_key.secret_access_key }}'
+          variable_key: env_var
+        body_format: form-urlencoded
+        headers: *gitlab_headers
+        method: POST
+        status_code: 201
+        url: "{{ gitlab_base_url }}/projects/{{ project_id }}/variables"
+
+    - name: Update the secret access key GitLab CI variable (will always change)
+      # yamllint disable-line rule:line-length
+      when: project_vars.json|selectattr("key", "equalto", "AWS_SECRET_ACCESS_KEY")|length == 1
+      changed_when: true
+      ansible.builtin.uri:
+        body:
+          environment_scope: "*"
+          masked: true
+          protected: false
+          value: '{{ aws_access_key.secret_access_key }}'
+          variable_key: env_var
+        body_format: form-urlencoded
+        headers: *gitlab_headers
+        method: PUT
+        status_code: 200
+        # yamllint disable-line rule:line-length
+        url: "{{ gitlab_base_url }}/projects/{{ project_id }}/variables/AWS_SECRET_ACCESS_KEY"
+
+    - name: Find all of the IAM access keys for the user
+      community.aws.iam_access_key_info:
+        user_name: '{{ aws_username }}'
+      register: aws_access_keys
+
+    - name: Remove the old IAM access keys
+      when: aws_access_keys.access_keys|length > 1
+      community.aws.iam_access_key:
+        id: '{{ access_key.access_key_id }}'
+        state: absent
+        user_name: '{{ aws_username }}'
+      vars:
+        # yamllint disable rule:line-length
+        access_key: >-
+          {{
+            aws_access_keys.access_keys|
+            rejectattr("access_key_id", "equalto", aws_access_key.access_key_id)|
+            first
+          }}
+        # yamllint enable rule:line-length
+
+    - name: AWS console URL for modifying the IAM user
+      debug:
+        # yamllint disable-line rule:line-length
+        msg: https://us-east-1.console.aws.amazon.com/iam/home#/users/{{ aws_username }}
+        verbosity: 0
diff --git a/Ansible/requirements.yml b/Ansible/requirements.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f56a5b3739c34fc2778ec17cbcfc9ffe025f066e
--- /dev/null
+++ b/Ansible/requirements.yml
@@ -0,0 +1,6 @@
+---
+collections:
+  - name: amazon.aws
+    version: '>=3.2.0'
+  - name: community.aws
+    version: '>=3.2.0'