diff --git a/app/finders/clusters/agents_finder.rb b/app/finders/clusters/agents_finder.rb
index d0b1240157c19de6a1c8f8941c762ae6c9baf6b8..8bc78300a44d04a245edefbfaccd99539db4c72b 100644
--- a/app/finders/clusters/agents_finder.rb
+++ b/app/finders/clusters/agents_finder.rb
@@ -4,8 +4,8 @@ module Clusters
   class AgentsFinder
     include FinderMethods
 
-    def initialize(project, current_user, params: {})
-      @project = project
+    def initialize(object, current_user, params: {})
+      @object = object
       @current_user = current_user
       @params = params
     end
@@ -13,7 +13,7 @@ def initialize(project, current_user, params: {})
     def execute
       return ::Clusters::Agent.none unless can_read_cluster_agents?
 
-      agents = project.cluster_agents
+      agents = object.cluster_agents
       agents = agents.with_name(params[:name]) if params[:name].present?
 
       agents.ordered_by_name
@@ -21,10 +21,10 @@ def execute
 
     private
 
-    attr_reader :project, :current_user, :params
+    attr_reader :object, :current_user, :params
 
     def can_read_cluster_agents?
-      current_user.can?(:read_cluster, project)
+      current_user&.can?(:read_cluster, object)
     end
   end
 end
diff --git a/app/graphql/resolvers/clusters/agents_resolver.rb b/app/graphql/resolvers/clusters/agents_resolver.rb
index 28618bef80751631d7d44fa657dce3f520509c32..81cea24194453d0cf3793533ac2753a3d4b96f2d 100644
--- a/app/graphql/resolvers/clusters/agents_resolver.rb
+++ b/app/graphql/resolvers/clusters/agents_resolver.rb
@@ -15,12 +15,10 @@ class AgentsResolver < BaseResolver
             description: 'Name of the cluster agent.'
       end
 
-      alias_method :project, :object
-
       def resolve_with_lookahead(**args)
         apply_lookahead(
           ::Clusters::AgentsFinder
-            .new(project, current_user, params: args)
+            .new(object, current_user, params: args)
             .execute
         )
       end
diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb
index fb12ce7d29286ef9f212e7eeca26421abef47f69..3478bb697075c3ef96e50cebea5410538910e9c2 100644
--- a/app/models/clusters/agent.rb
+++ b/app/models/clusters/agent.rb
@@ -53,3 +53,5 @@ def to_ability_name
     end
   end
 end
+
+Clusters::Agent.prepend_mod_with('Clusters::Agent')
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index cc24847c3f0bb56484b7475d24c413267d02c1f2..3fc104f873f4b034b238ad3fbaa4c43f19f0b8ca 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -11694,6 +11694,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
 | <a id="groupallowstalerunnerpruning"></a>`allowStaleRunnerPruning` | [`Boolean!`](#boolean) | Indicates whether to regularly prune stale group runners. Defaults to false. |
 | <a id="groupautodevopsenabled"></a>`autoDevopsEnabled` | [`Boolean`](#boolean) | Indicates whether Auto DevOps is enabled for all projects within this group. |
 | <a id="groupavatarurl"></a>`avatarUrl` | [`String`](#string) | Avatar URL of the group. |
+| <a id="groupclusteragents"></a>`clusterAgents` | [`ClusterAgentConnection`](#clusteragentconnection) | Cluster agents associated with projects in the group and its subgroups. (see [Connections](#connections)) |
 | <a id="groupcontainerrepositoriescount"></a>`containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the group. |
 | <a id="groupcontainslockedprojects"></a>`containsLockedProjects` | [`Boolean!`](#boolean) | Includes at least one project where the repository size exceeds the limit. |
 | <a id="groupcrossprojectpipelineavailable"></a>`crossProjectPipelineAvailable` | [`Boolean!`](#boolean) | Indicates if the cross_project_pipeline feature is available for the namespace. |
@@ -12573,6 +12574,7 @@ A block of time for which a participant is on-call.
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
+| <a id="instancesecuritydashboardclusteragents"></a>`clusterAgents` | [`ClusterAgentConnection`](#clusteragentconnection) | Cluster agents associated with projects selected in the Instance Security Dashboard. (see [Connections](#connections)) |
 | <a id="instancesecuritydashboardvulnerabilitygrades"></a>`vulnerabilityGrades` | [`[VulnerableProjectsByGrade!]!`](#vulnerableprojectsbygrade) | Represents vulnerable project counts for each grade. |
 | <a id="instancesecuritydashboardvulnerabilityscanners"></a>`vulnerabilityScanners` | [`VulnerabilityScannerConnection`](#vulnerabilityscannerconnection) | Vulnerability scanners reported on the vulnerabilities from projects selected in Instance Security Dashboard. (see [Connections](#connections)) |
 
diff --git a/ee/app/graphql/ee/types/group_type.rb b/ee/app/graphql/ee/types/group_type.rb
index 3445369121aa326765a30811404899b53aa059f0..d03ca4b72996b95e26ff0d47aff428a6dc940cb3 100644
--- a/ee/app/graphql/ee/types/group_type.rb
+++ b/ee/app/graphql/ee/types/group_type.rb
@@ -115,6 +115,13 @@ module GroupType
               description: 'Indicates whether to regularly prune stale group runners. Defaults to false.',
               method: :allow_stale_runner_pruning?
 
+        field :cluster_agents,
+              ::Types::Clusters::AgentType.connection_type,
+              extras: [:lookahead],
+              null: true,
+              description: 'Cluster agents associated with projects in the group and its subgroups.',
+              resolver: ::Resolvers::Clusters::AgentsResolver
+
         def billable_members_count(requested_hosted_plan: nil)
           object.billable_members_count(requested_hosted_plan)
         end
diff --git a/ee/app/graphql/types/instance_security_dashboard_type.rb b/ee/app/graphql/types/instance_security_dashboard_type.rb
index bcec5f4f7efb968bcb178360ccab5217bc910f1b..8f81ce587dca560c8b2ddcf7184f188405250046 100644
--- a/ee/app/graphql/types/instance_security_dashboard_type.rb
+++ b/ee/app/graphql/types/instance_security_dashboard_type.rb
@@ -27,6 +27,13 @@ class InstanceSecurityDashboardType < BaseObject
           null: false,
           description: 'Represents vulnerable project counts for each grade.'
 
+    field :cluster_agents,
+          ::Types::Clusters::AgentType.connection_type,
+          extras: [:lookahead],
+          null: true,
+          description: 'Cluster agents associated with projects selected in the Instance Security Dashboard.',
+          resolver: ::Resolvers::Clusters::AgentsResolver
+
     def vulnerability_grades
       ::Gitlab::Graphql::Aggregations::VulnerabilityStatistics::LazyAggregate.new(
         context,
diff --git a/ee/app/models/ee/clusters/agent.rb b/ee/app/models/ee/clusters/agent.rb
new file mode 100644
index 0000000000000000000000000000000000000000..aec39fb38f7ea01914a07947271834844dccf3ce
--- /dev/null
+++ b/ee/app/models/ee/clusters/agent.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module EE
+  module Clusters
+    module Agent
+      extend ActiveSupport::Concern
+
+      prepended do
+        scope :for_projects, -> (projects) { where(project: projects) }
+      end
+    end
+  end
+end
diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb
index 42d8c448f855e0aade0c7c58b5347f596d893dfc..9d72dda8d51cbc49ba80d42fb6d3771a6da6319c 100644
--- a/ee/app/models/ee/group.rb
+++ b/ee/app/models/ee/group.rb
@@ -630,6 +630,10 @@ def shared_externally?
       end
     end
 
+    def cluster_agents
+      ::Clusters::Agent.for_projects(all_projects)
+    end
+
     private
 
     override :post_create_hook
diff --git a/ee/app/models/instance_security_dashboard.rb b/ee/app/models/instance_security_dashboard.rb
index 05c3f05f9cd7e60a19164e6d5193f3d9d4c925a7..e4cbb2fc52752e5b4a8463ebdc57e9b23f624f05 100644
--- a/ee/app/models/instance_security_dashboard.rb
+++ b/ee/app/models/instance_security_dashboard.rb
@@ -51,6 +51,12 @@ def has_projects?
     projects.count > 0
   end
 
+  def cluster_agents
+    return Clusters::Agent.none if projects.empty?
+
+    Clusters::Agent.for_projects(projects)
+  end
+
   private
 
   attr_reader :project_ids, :user
diff --git a/ee/spec/factories/vulnerabilities/findings.rb b/ee/spec/factories/vulnerabilities/findings.rb
index 63296040587d5de9557a04d5cdbffa18c2238157..67c2c754968bd60fa108fb2088d237428a35b6a1 100644
--- a/ee/spec/factories/vulnerabilities/findings.rb
+++ b/ee/spec/factories/vulnerabilities/findings.rb
@@ -577,6 +577,7 @@
     trait :with_cluster_image_scanning_scanning_metadata do
       transient do
         location_image { "alpine:3.7" }
+        agent_id { '46357' }
       end
 
       after(:build) do |finding, evaluator|
@@ -594,7 +595,7 @@
           "image": evaluator.location_image,
           "kubernetes_resource": {
             "cluster_id": "1",
-            "agent_id": "46357"
+            "agent_id": evaluator.agent_id
           }
         }
         finding.raw_metadata = {
diff --git a/ee/spec/graphql/ee/types/group_type_spec.rb b/ee/spec/graphql/ee/types/group_type_spec.rb
index 8420f541765dbd4f8da37fd273fac6259837a30c..8aa3f45292a884fa165c9b01a2bb5d6279620c1b 100644
--- a/ee/spec/graphql/ee/types/group_type_spec.rb
+++ b/ee/spec/graphql/ee/types/group_type_spec.rb
@@ -23,6 +23,7 @@
   it { expect(described_class).to have_graphql_field(:external_audit_event_destinations) }
   it { expect(described_class).to have_graphql_field(:merge_request_violations) }
   it { expect(described_class).to have_graphql_field(:allow_stale_runner_pruning) }
+  it { expect(described_class).to have_graphql_field(:cluster_agents) }
 
   describe 'vulnerabilities' do
     let_it_be(:group) { create(:group) }
diff --git a/ee/spec/graphql/resolvers/clusters/agents_resolver_spec.rb b/ee/spec/graphql/resolvers/clusters/agents_resolver_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b621122c5e9e2e3c4b1534b8fc473749beb34b6d
--- /dev/null
+++ b/ee/spec/graphql/resolvers/clusters/agents_resolver_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Clusters::AgentsResolver do
+  include GraphqlHelpers
+
+  specify do
+    expect(described_class).to have_nullable_graphql_type(Types::Clusters::AgentType.connection_type)
+  end
+
+  specify do
+    expect(described_class.field_options).to include(extras: include(:lookahead))
+  end
+
+  describe '#resolve' do
+    let_it_be(:project) { create(:project) }
+    let_it_be(:maintainer) { create(:user, developer_projects: [project]) }
+    let_it_be(:reporter) { create(:user) }
+
+    let_it_be(:agent_1) { create(:cluster_agent, project: project) }
+    let_it_be(:agent_2) { create(:cluster_agent, project: project) }
+
+    before do
+      project.add_reporter(reporter)
+    end
+
+    let(:ctx) { { current_user: current_user } }
+    let(:params) { {} }
+
+    subject { resolve_agents(params) }
+
+    context 'the current user has access to clusters' do
+      let(:current_user) { maintainer }
+
+      it 'finds all agents' do
+        expect(subject).to contain_exactly(agent_1, agent_2)
+      end
+    end
+
+    context 'the current user does not have access to clusters' do
+      let(:current_user) { reporter }
+
+      it 'returns an empty result' do
+        expect(subject).to be_empty
+      end
+    end
+  end
+
+  def resolve_agents(args = {})
+    resolve(described_class, obj: project, ctx: ctx, lookahead: positive_lookahead, args: args)
+  end
+end
diff --git a/ee/spec/graphql/types/instance_security_dashboard_type_spec.rb b/ee/spec/graphql/types/instance_security_dashboard_type_spec.rb
index d1c42d7a2c6344ee155dc712aaf249174b6f4731..d332c4442da8e442d2d264543d28839934b84639 100644
--- a/ee/spec/graphql/types/instance_security_dashboard_type_spec.rb
+++ b/ee/spec/graphql/types/instance_security_dashboard_type_spec.rb
@@ -8,7 +8,7 @@
   let_it_be(:user) { create(:user, security_dashboard_projects: [project]) }
 
   let(:fields) do
-    %i[projects vulnerability_scanners vulnerability_severities_count vulnerability_grades]
+    %i[projects vulnerability_scanners vulnerability_severities_count vulnerability_grades cluster_agents]
   end
 
   before do
diff --git a/ee/spec/models/ee/clusters/agent_spec.rb b/ee/spec/models/ee/clusters/agent_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a41591bf56fa8755705da38060f077e7563a5754
--- /dev/null
+++ b/ee/spec/models/ee/clusters/agent_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Clusters::Agent do
+  it { is_expected.to include_module(EE::Clusters::Agent) }
+
+  describe '.for_projects' do
+    let_it_be(:agent_1) { create(:cluster_agent) }
+    let_it_be(:agent_2) { create(:cluster_agent) }
+    let_it_be(:agent_3) { create(:cluster_agent) }
+
+    it 'return agents for selected projects' do
+      expect(described_class.for_projects([agent_1.project, agent_3.project])).to contain_exactly(agent_1, agent_3)
+    end
+  end
+end
diff --git a/ee/spec/models/ee/group_spec.rb b/ee/spec/models/ee/group_spec.rb
index 0d56b324a098092bce16a50c9b221b552a768f6e..52a0c42ec17e6083b0c4be47783aa02c5728646f 100644
--- a/ee/spec/models/ee/group_spec.rb
+++ b/ee/spec/models/ee/group_spec.rb
@@ -2524,4 +2524,22 @@ def webhook_headers
         .to contain_exactly(project_user.id, owner1.id, owner2.id, project2_user.id, bot_project_user.id, requesting_user.id, group_user.id)
     end
   end
+
+  describe '#cluster_agents' do
+    let_it_be(:other_group) { create(:group) }
+    let_it_be(:other_project) { create(:project, namespace: other_group) }
+
+    let_it_be(:root_group) { create(:group) }
+    let_it_be(:subgroup) { create(:group, parent: root_group) }
+    let_it_be(:project_in_group) { create(:project, namespace: root_group) }
+    let_it_be(:project_in_subgroup) { create(:project, namespace: subgroup) }
+
+    let_it_be(:cluster_agent_for_other_project) { create(:cluster_agent, project: other_project) }
+    let_it_be(:cluster_agent_for_project) { create(:cluster_agent, project: project_in_group) }
+    let_it_be(:cluster_agent_for_project_in_subgroup) { create(:cluster_agent, project: project_in_subgroup) }
+
+    subject { root_group.cluster_agents }
+
+    it { is_expected.to contain_exactly(cluster_agent_for_project, cluster_agent_for_project_in_subgroup) }
+  end
 end
diff --git a/ee/spec/models/instance_security_dashboard_spec.rb b/ee/spec/models/instance_security_dashboard_spec.rb
index 3664bf57ee27dbe9db99d708b766289e1eba26d8..72256141c600a857f2cc3d4c88036db886a5c16d 100644
--- a/ee/spec/models/instance_security_dashboard_spec.rb
+++ b/ee/spec/models/instance_security_dashboard_spec.rb
@@ -217,6 +217,23 @@
     end
   end
 
+  describe '#cluster_agents' do
+    let_it_be(:cluster_agent_for_project_1) { create(:cluster_agent, project: project1) }
+    let_it_be(:cluster_agent_for_project_3) { create(:cluster_agent, project: project3) }
+
+    context 'when instance security dashboard has projects added' do
+      it { expect(instance_dashboard.cluster_agents).to contain_exactly(cluster_agent_for_project_1) }
+    end
+
+    context 'when instance security dashboard does not have any projects added' do
+      let_it_be(:other_user) { create(:user) }
+
+      subject(:instance_dashboard) { described_class.new(other_user, project_ids: []) }
+
+      it { expect(instance_dashboard.cluster_agents).to be_empty }
+    end
+  end
+
   describe '#full_path' do
     let(:user) { create(:user) }