diff --git a/CHANGELOG b/CHANGELOG
index d073ef013614c20ac728b4e5e2d17ed90a2b30db..2ae6af7ab6b8df8aa50b15d3ba2aa3b96d72d876 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -86,6 +86,7 @@ v 8.10.0 (unreleased)
   - More descriptive message for git hooks and file locks
   - Aliases of award emoji should be stored as original name. !5060 (dixpac)
   - Handle custom Git hook result in GitLab UI
+  - Allow to access Container Registry for Public and Internal projects
   - Allow '?', or '&' for label names
   - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests
   - Add date when user joined the team on the member page
diff --git a/app/models/ability.rb b/app/models/ability.rb
index eeb0ceba08113b9d385ee63cbfb8b3cf30dc3dc9..6fd18f2ee24bd0dea3b42d0aff4c9317eeac8534 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -204,7 +204,8 @@ class Ability
         :download_code,
         :fork_project,
         :read_commit_status,
-        :read_pipeline
+        :read_pipeline,
+        :read_container_image
       ]
     end
 
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 13d980a326f512f9656c16e6a1dc3e0e808b9e2f..b6acc509342af993f534b124a8faf6f065a42b93 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -426,4 +426,23 @@ describe "Internal Project Access", feature: true  do
     it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
+
+  describe "GET /:project_path/container_registry" do
+    before do
+      stub_container_registry_tags('latest')
+      stub_container_registry_config(enabled: true)
+    end
+
+    subject { namespace_project_container_registry_index_path(project.namespace, project) }
+
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for owner }
+    it { is_expected.to be_allowed_for master }
+    it { is_expected.to be_allowed_for developer }
+    it { is_expected.to be_allowed_for reporter }
+    it { is_expected.to be_allowed_for guest }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_denied_for :visitor }
+  end
 end
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index ac9690cc12796f7001a98cfe7efd2df49229018f..ccb5c06dab013144d0d6974d892a9ecb40357954 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -362,4 +362,23 @@ describe "Private Project Access", feature: true  do
     it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
+
+  describe "GET /:project_path/container_registry" do
+    before do
+      stub_container_registry_tags('latest')
+      stub_container_registry_config(enabled: true)
+    end
+
+    subject { namespace_project_container_registry_index_path(project.namespace, project) }
+
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for owner }
+    it { is_expected.to be_allowed_for master }
+    it { is_expected.to be_allowed_for developer }
+    it { is_expected.to be_allowed_for reporter }
+    it { is_expected.to be_denied_for guest }
+    it { is_expected.to be_denied_for :user }
+    it { is_expected.to be_denied_for :external }
+    it { is_expected.to be_denied_for :visitor }
+  end
 end
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 737897de52b694b006a7043b5053be28206569ec..985663e7c989a4c9d76bd9bdab53c99ebb2819a2 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -426,4 +426,23 @@ describe "Public Project Access", feature: true  do
     it { is_expected.to be_denied_for :external }
     it { is_expected.to be_denied_for :visitor }
   end
+
+  describe "GET /:project_path/container_registry" do
+    before do
+      stub_container_registry_tags('latest')
+      stub_container_registry_config(enabled: true)
+    end
+
+    subject { namespace_project_container_registry_index_path(project.namespace, project) }
+
+    it { is_expected.to be_allowed_for :admin }
+    it { is_expected.to be_allowed_for owner }
+    it { is_expected.to be_allowed_for master }
+    it { is_expected.to be_allowed_for developer }
+    it { is_expected.to be_allowed_for reporter }
+    it { is_expected.to be_allowed_for guest }
+    it { is_expected.to be_allowed_for :user }
+    it { is_expected.to be_allowed_for :external }
+    it { is_expected.to be_allowed_for :visitor }
+  end
 end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 67777ad48bc69c45cd164c99f8297ea9c998d502..7cc71f706ce6c9638b473408ece6f204d5335125 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -87,51 +87,105 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
   end
 
   context 'user authorization' do
-    let(:project) { create(:project) }
     let(:current_user) { create(:user) }
 
-    context 'allow to use scope-less authentication' do
-      it_behaves_like 'a valid token'
-    end
+    context 'for private project' do
+      let(:project) { create(:empty_project) }
 
-    context 'allow developer to push images' do
-      before { project.team << [current_user, :developer] }
+      context 'allow to use scope-less authentication' do
+        it_behaves_like 'a valid token'
+      end
 
-      let(:current_params) do
-        { scope: "repository:#{project.path_with_namespace}:push" }
+      context 'allow developer to push images' do
+        before { project.team << [current_user, :developer] }
+
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:push" }
+        end
+
+        it_behaves_like 'a pushable'
       end
 
-      it_behaves_like 'a pushable'
-    end
+      context 'allow reporter to pull images' do
+        before { project.team << [current_user, :reporter] }
+
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:pull" }
+        end
 
-    context 'allow reporter to pull images' do
-      before { project.team << [current_user, :reporter] }
+        it_behaves_like 'a pullable'
+      end
 
-      let(:current_params) do
-        { scope: "repository:#{project.path_with_namespace}:pull" }
+      context 'return a least of privileges' do
+        before { project.team << [current_user, :reporter] }
+
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:push,pull" }
+        end
+
+        it_behaves_like 'a pullable'
       end
 
-      it_behaves_like 'a pullable'
+      context 'disallow guest to pull or push images' do
+        before { project.team << [current_user, :guest] }
+
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:pull,push" }
+        end
+
+        it_behaves_like 'an inaccessible'
+      end
     end
 
-    context 'return a least of privileges' do
-      before { project.team << [current_user, :reporter] }
+    context 'for public project' do
+      let(:project) { create(:empty_project, :public) }
 
-      let(:current_params) do
-        { scope: "repository:#{project.path_with_namespace}:push,pull" }
+      context 'allow anyone to pull images' do
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:pull" }
+        end
+
+        it_behaves_like 'a pullable'
       end
 
-      it_behaves_like 'a pullable'
+      context 'disallow anyone to push images' do
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:push" }
+        end
+
+        it_behaves_like 'an inaccessible'
+      end
     end
 
-    context 'disallow guest to pull or push images' do
-      before { project.team << [current_user, :guest] }
+    context 'for internal project' do
+      let(:project) { create(:empty_project, :internal) }
 
-      let(:current_params) do
-        { scope: "repository:#{project.path_with_namespace}:pull,push" }
+      context 'for internal user' do
+        context 'allow anyone to pull images' do
+          let(:current_params) do
+            { scope: "repository:#{project.path_with_namespace}:pull" }
+          end
+
+          it_behaves_like 'a pullable'
+        end
+
+        context 'disallow anyone to push images' do
+          let(:current_params) do
+            { scope: "repository:#{project.path_with_namespace}:push" }
+          end
+
+          it_behaves_like 'an inaccessible'
+        end
       end
 
-      it_behaves_like 'an inaccessible'
+      context 'for external user' do
+        let(:current_user) { create(:user, external: true) }
+        let(:current_params) do
+          { scope: "repository:#{project.path_with_namespace}:pull,push" }
+        end
+
+        it_behaves_like 'an inaccessible'
+      end
     end
   end