diff --git a/cloud.routing.yml b/cloud.routing.yml
index adfadc3d29d3c16f1d5517bdd40e9184c32db197..fa72ee538b3646e68680d8f07af72ef041a67b94 100644
--- a/cloud.routing.yml
+++ b/cloud.routing.yml
@@ -16,7 +16,7 @@ entity.cloud_server_template.collection:
   requirements:
     # Use custom access that will check for cloud_context and the desired permission.
     # Desired permission is passed as an option in the "perm" variable
-    _custom_access: '\Drupal\cloud\Controller\CloudConfigController::access'
+    _custom_access: '\Drupal\cloud\Controller\CloudServerTemplateController::access'
   options:
       perm: 'list cloud server template'
 
@@ -31,7 +31,7 @@ entity.cloud_server_template.add_form:
   requirements:
     # Use custom access that will check for cloud_context and the desired permission.
     # Desired permission is passed as an option in the "perm" variable
-    _custom_access: '\Drupal\cloud\Controller\CloudConfigController::access'
+    _custom_access: '\Drupal\cloud\Controller\CloudServerTemplateController::access'
   options:
       perm: 'add cloud server templates'
       parameters:
diff --git a/modules/cloud_service_providers/aws_cloud/aws_cloud.module b/modules/cloud_service_providers/aws_cloud/aws_cloud.module
index e67be28e8195dc555ab16fed4809eaa3970f32f8..14879da6044e62de74bd6105ca381b74d4a774af 100644
--- a/modules/cloud_service_providers/aws_cloud/aws_cloud.module
+++ b/modules/cloud_service_providers/aws_cloud/aws_cloud.module
@@ -476,6 +476,9 @@ function aws_cloud_get_iam_roles($cloud_context): array {
   $iam_service->setCloudContext($cloud_context);
   // Don't show API errors when the page first loads.
   $response = $iam_service->listInstanceProfiles([], [], FALSE);
+  if (empty($response)) {
+    return $roles;
+  }
   foreach ($response['InstanceProfiles'] ?: [] as $instance_profile) {
     // Skip profiles without a role.
     if (empty($instance_profile['Roles'])) {
diff --git a/modules/cloud_service_providers/aws_cloud/aws_cloud.services.yml b/modules/cloud_service_providers/aws_cloud/aws_cloud.services.yml
index 5c51c566013830d9d4cf232f4e0dd856975fa3b8..c3eb2283a7630b2e1a7a8679bfd952f13ba7247a 100644
--- a/modules/cloud_service_providers/aws_cloud/aws_cloud.services.yml
+++ b/modules/cloud_service_providers/aws_cloud/aws_cloud.services.yml
@@ -51,3 +51,7 @@ services:
   aws_cloud.low_utilization_instances_checker:
     class: Drupal\aws_cloud\Service\CloudWatch\LowUtilizationInstanceChecker
     arguments: ['@aws_cloud.cloud_watch', '@config.factory']
+
+  aws_cloud.access:
+    class: Drupal\aws_cloud\Access\AwsCloudAccess
+    arguments: ['@aws_cloud.ec2','@aws_cloud.iam']
\ No newline at end of file
diff --git a/modules/cloud_service_providers/aws_cloud/src/Access/AwsCloudAccess.php b/modules/cloud_service_providers/aws_cloud/src/Access/AwsCloudAccess.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a40543ca3b35cedcfe8ef01c80beb73fd8537ef
--- /dev/null
+++ b/modules/cloud_service_providers/aws_cloud/src/Access/AwsCloudAccess.php
@@ -0,0 +1,139 @@
+<?php
+
+namespace Drupal\aws_cloud\Access;
+
+use Aws\Exception\AwsException;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
+use Drupal\aws_cloud\Service\Iam\IamServiceInterface;
+use Drupal\cloud\Traits\CloudContentEntityTrait;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Access validation for Aws resource operations/forms.
+ *
+ * @package Drupal\aws_cloud\Access
+ */
+class AwsCloudAccess implements AwsCloudAccessInterface {
+
+  use CloudContentEntityTrait;
+
+  /**
+   * EC2 service.
+   *
+   * @var \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface
+   */
+  protected $ec2Service;
+
+  /**
+   * IAM service.
+   *
+   * @var \Drupal\aws_cloud\Service\Iam\IamServiceInterface
+   */
+  protected $iamService;
+
+  /**
+   * AwsCloudAccess constructor.
+   *
+   * @param \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface $ec2_service
+   *   The EC2 service.
+   * @param \Drupal\aws_cloud\Service\Iam\IamServiceInterface $iam_service
+   *   The IAM service.
+   */
+  public function __construct(Ec2ServiceInterface $ec2_service,
+                              IamServiceInterface $iam_service) {
+    $this->ec2Service = $ec2_service;
+    $this->iamService = $iam_service;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container): AwsCloudAccess {
+    return new static(
+      $container->get('aws_cloud.ec2'),
+      $container->get('aws_cloud.iam')
+    );
+  }
+
+  /**
+   * Validate IAM permissions by invoking AWS APIs.
+   *
+   * @param string $perm
+   *   Permission.
+   * @param \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface|\Drupal\aws_cloud\Service\Iam\IamServiceInterface $service
+   *   Service object, EC2 or IAM.
+   * @param string $cloud_context
+   *   Cloud context.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   Access result.
+   */
+  private function validateIamPermissions(string $perm, $service, string $cloud_context): AccessResultInterface {
+
+    // 1. Check arguments.
+    if (empty($perm)
+      || empty($cloud_context)) {
+      return AccessResult::allowed();
+    }
+
+    // 2. Check if $service is Ec2ServiceInterface or IamServiceInterface.
+    if (!($service instanceof Ec2ServiceInterface)
+      && !($service instanceof IamServiceInterface)) {
+      return AccessResult::allowed();
+    }
+
+    // 3. Check if $service::PERMISSION_TO_AWS_API[$perm] is valid or not.
+    if (is_array($service::PERMISSION_TO_AWS_API)
+      && !array_key_exists($perm, $service::PERMISSION_TO_AWS_API)) {
+      return AccessResult::allowed();
+    }
+
+    // 4. Set $cloud_context.
+    $service->setCloudContext($cloud_context);
+
+    // 5. Validate IAM permissions for AWS APIs.
+    $apis = (array) $service::PERMISSION_TO_AWS_API[$perm];
+    foreach ($apis as $api) {
+      try {
+        $method = lcfirst($api);
+        $service->$method(['DryRun' => TRUE]);
+      }
+      catch (AwsException $e) {
+        // If permission is granted, the error code is DryRunOperation.
+        // If not, the error code is one of permissionErrorCodes.
+        $error_code = $e->getAwsErrorCode();
+
+        if (in_array($error_code, $service::PERMISSION_ERROR_CODES, TRUE)) {
+          $this->logger('aws_cloud')->error($e->getMessage());
+          return AccessResult::forbidden();
+        }
+        // Other error code means an unexpected error occurs.
+        // @FIXME This condition will be cleaned once AWS-service-related
+        // constants are better defined.
+        if ($service instanceof IamServiceInterface
+          || $error_code !== Ec2ServiceInterface::DRY_RUN_OPERATION) {
+          $this->logger('aws_cloud')->error($e->getMessage());
+        }
+      }
+      catch (\Exception $e) {
+        // Continue processing even if unexpected exceptions occur.
+        $this->logger('aws_cloud')->error($e->getMessage());
+      }
+    }
+    return AccessResult::allowed();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    $perm = $route->getOption('perm');
+    return $this->validateIamPermissions($perm, $this->ec2Service, $cloud_context)
+      ->andIf($this->validateIamPermissions($perm, $this->iamService, $cloud_context));
+  }
+
+}
diff --git a/modules/cloud_service_providers/aws_cloud/src/Access/AwsCloudAccessInterface.php b/modules/cloud_service_providers/aws_cloud/src/Access/AwsCloudAccessInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2de32efa015647a3d55ccbeb8587498f6160a3d
--- /dev/null
+++ b/modules/cloud_service_providers/aws_cloud/src/Access/AwsCloudAccessInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\aws_cloud\Access;
+
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Interface AwsCloudAccessInterface for access control.
+ *
+ * @package Drupal\aws_cloud\Controller
+ */
+interface AwsCloudAccessInterface {
+
+  /**
+   * Checks user access by both Drupal and IAM permissions.
+   *
+   * @param string $cloud_context
+   *   Cloud context to check.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   Run access checks for this account.
+   * @param \Symfony\Component\Routing\Route $route
+   *   The route object.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface;
+
+}
diff --git a/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/config/AwsCloudConfigPlugin.php b/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/config/AwsCloudConfigPlugin.php
index 5d839541334eaf437606744c2139f0025318e79f..2e690e550cf33801a0742eb107f458a84f661b25 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/config/AwsCloudConfigPlugin.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/config/AwsCloudConfigPlugin.php
@@ -2,13 +2,17 @@
 
 namespace Drupal\aws_cloud\Plugin\cloud\config;
 
+use Drupal\aws_cloud\Access\AwsCloudAccessInterface;
 use Drupal\aws_cloud\Entity\Ec2\AwsCloudEntityInterface;
 use Drupal\cloud\Plugin\cloud\CloudPluginBase;
 use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginInterface;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\File\FileSystem;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * AWS Cloud cloud service provider (CloudConfig) plugin.
@@ -29,6 +33,13 @@ class AwsCloudConfigPlugin extends CloudPluginBase implements CloudConfigPluginI
    */
   protected $fileSystem;
 
+  /**
+   * AWS Cloud Access Controller.
+   *
+   * @var Drupal\aws_cloud\Access\AwsCloudAccessInterface
+   */
+  protected $awsCloudAccess;
+
   /**
    * AwsCloudConfigPlugin constructor.
    *
@@ -42,16 +53,19 @@ class AwsCloudConfigPlugin extends CloudPluginBase implements CloudConfigPluginI
    *   The Entity type manager.
    * @param \Drupal\Core\File\FileSystem $fileSystem
    *   The FileSystem object.
+   * @param \Drupal\aws_cloud\Access\AwsCloudAccessInterface $aws_cloud_access
+   *   The AwsCloudAccess object.
    */
   public function __construct(array $configuration,
                               $plugin_id,
                               $plugin_definition,
                               EntityTypeManagerInterface $entityTypeManager,
-                              FileSystem $fileSystem) {
+                              FileSystem $fileSystem,
+                              AwsCloudAccessInterface $aws_cloud_access) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-
     $this->entityTypeManager = $entityTypeManager;
     $this->fileSystem = $fileSystem;
+    $this->awsCloudAccess = $aws_cloud_access;
   }
 
   /**
@@ -63,7 +77,8 @@ class AwsCloudConfigPlugin extends CloudPluginBase implements CloudConfigPluginI
       $plugin_id,
       $plugin_definition,
       $container->get('entity_type.manager'),
-      $container->get('file_system')
+      $container->get('file_system'),
+      $container->get('aws_cloud.access')
     );
   }
 
@@ -170,4 +185,11 @@ class AwsCloudConfigPlugin extends CloudPluginBase implements CloudConfigPluginI
     return AwsCloudEntityInterface::TAG_CREATED_BY_UID;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return $this->awsCloudAccess->access($cloud_context, $account, $route);
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/server_template/AwsCloudServerTemplatePlugin.php b/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/server_template/AwsCloudServerTemplatePlugin.php
index b36e462eb0d889b35556b4fa4709c19543046863..fda3bae8eeae70fdd34c9d330315c4bf498930bb 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/server_template/AwsCloudServerTemplatePlugin.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Plugin/cloud/server_template/AwsCloudServerTemplatePlugin.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\aws_cloud\Plugin\cloud\server_template;
 
+use Drupal\aws_cloud\Access\AwsCloudAccessInterface;
 use Drupal\aws_cloud\Entity\Ec2\Instance;
 use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\cloud\Entity\CloudServerTemplate;
@@ -11,6 +12,7 @@ use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManagerInterface;
 use Drupal\cloud\Plugin\cloud\server_template\CloudServerTemplatePluginInterface;
 use Drupal\cloud\Service\EntityLinkRendererInterface;
 use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -18,10 +20,12 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Link;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Drupal\cloud\Service\CloudServiceInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * AWS Cloud cloud launch template plugin.
@@ -91,6 +95,13 @@ class AwsCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
    */
   protected $cloudService;
 
+  /**
+   * AWS Cloud Access.
+   *
+   * @var Drupal\aws_cloud\Access\AwsCloudAccessInterface
+   */
+  protected $awsCloudAccess;
+
   /**
    * AwsCloudServerTemplatePlugin constructor.
    *
@@ -118,6 +129,8 @@ class AwsCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
    *   The route match.
    * @param \Drupal\cloud\Service\CloudServiceInterface $cloud_service
    *   The Cloud service.
+   * @param \Drupal\aws_cloud\Access\AwsCloudAccessInterface $aws_cloud_access
+   *   The AwsCloudAccess object.
    */
   public function __construct(array $configuration,
                               $plugin_id,
@@ -130,7 +143,8 @@ class AwsCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
                               CloudConfigPluginManagerInterface $cloud_config_plugin_manager,
                               EntityLinkRendererInterface $entity_link_renderer,
                               RouteMatchInterface $route_match,
-                              CloudServiceInterface $cloud_service) {
+                              CloudServiceInterface $cloud_service,
+                              AwsCloudAccessInterface $aws_cloud_access) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->ec2Service = $ec2_service;
@@ -142,6 +156,7 @@ class AwsCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
     $this->entityLinkRenderer = $entity_link_renderer;
     $this->routeMatch = $route_match;
     $this->cloudService = $cloud_service;
+    $this->awsCloudAccess = $aws_cloud_access;
   }
 
   /**
@@ -161,6 +176,7 @@ class AwsCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
       $container->get('entity.link_renderer'),
       $container->get('current_route_match'),
       $container->get('cloud'),
+      $container->get('aws_cloud.access')
     );
   }
 
@@ -1022,4 +1038,11 @@ class AwsCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
     return $updated;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return $this->awsCloudAccess->access($cloud_context, $account, $route);
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2Service.php b/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2Service.php
index 184e405207944222adb6ff33bcedc0289b6c6880..74e4511847912521e5c89a1671cf85e6c8fa0445 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2Service.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2Service.php
@@ -16,6 +16,7 @@ use Drupal\aws_cloud\Entity\Ec2\Instance;
 use Drupal\cloud\Entity\CloudConfigInterface;
 use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManagerInterface;
 use Drupal\cloud\Service\CloudServiceBase;
+use Drupal\Component\Utility\Random;
 use Drupal\Core\Batch\BatchBuilder;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
@@ -125,6 +126,13 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    */
   protected $cloudService;
 
+  /**
+   * Random instance.
+   *
+   * @var \Drupal\Component\Utility\Random
+   */
+  protected $random;
+
   /**
    * Constructs a new Ec2Service object.
    *
@@ -181,6 +189,7 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
     $this->queueFactory = $queue_factory;
     $this->httpClient = $http_client;
     $this->cloudService = $cloud_service;
+    $this->random = new Random();
   }
 
   /**
@@ -320,14 +329,14 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
       $command_name = $command->getName();
       $response_data = $mock_data[$command_name] ?? [];
 
-      // ErrorCode field is proprietary defined to mock AwsException.
+      // ErrorCode field is proprietary defined to mock AwsErrorCode.
       // Checking the value of DryRun parameter as some test cases expect a
       // different result based on the DryRun parameter.
       if (!empty($response_data['ErrorCode'])
         && $command->hasParam('DryRun')
         && ($command->toArray())['DryRun']) {
-        return new Ec2Exception('Ec2Exception by Ec2Service::addMockHandler()',
-          $command, ['code' => $response_data['ErrorCode']]);
+        return new Ec2ServiceException('AwsException on ' . $command_name . ' by Ec2Service::addMockHandler()',
+          $command_name, $response_data['ErrorCode']);
       }
 
       // Support EC2-Classic.
@@ -396,7 +405,7 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
 
     $ec2_client = $this->getEc2Client($credentials);
     if (empty($ec2_client)) {
-      throw new Ec2ServiceException('No EC2 Client found.  Cannot perform API operations');
+      throw new Ec2ServiceException('No EC2 Client found. Cannot perform API operations');
     }
 
     try {
@@ -447,7 +456,7 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
       catch (\Exception $ex) {
         // If an error occurs, display the error message.
         $check_iam_permissions = TRUE;
-        \Drupal::logger('aws_cloud')->error($ex->getMessage());
+        $this->logger('aws_cloud')->error($ex->getMessage());
       }
 
       // If check permissions is FALSE, no need to display these error messages.
@@ -481,6 +490,7 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
     }
     catch (\Exception $e) {
       $this->handleException($e);
+      $this->logger('aws_cloud')->error($e->getMessage());
     }
     return $results;
   }
@@ -489,7 +499,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function associateAddress(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AssociateAddress', $params);
   }
 
@@ -497,7 +506,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function allocateAddress(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AllocateAddress', $params);
   }
 
@@ -505,7 +513,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function associateIamInstanceProfile(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AssociateIamInstanceProfile', $params);
   }
 
@@ -513,7 +520,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeAccountAttributes(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeAccountAttributes', $params, $credentials);
   }
 
@@ -521,7 +527,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function disassociateIamInstanceProfile(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DisassociateIamInstanceProfile', $params);
   }
 
@@ -529,7 +534,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function replaceIamInstanceProfileAssociation(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ReplaceIamInstanceProfileAssociation', $params);
   }
 
@@ -537,7 +541,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeIamInstanceProfileAssociations(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeIamInstanceProfileAssociations', $params, $credentials);
   }
 
@@ -545,7 +548,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function authorizeSecurityGroupIngress(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AuthorizeSecurityGroupIngress', $params, $credentials);
   }
 
@@ -553,23 +555,27 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function authorizeSecurityGroupEgress(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AuthorizeSecurityGroupEgress', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createImage(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateImage', $params);
+  public function createImage(array $params = [], array $credentials = []): ?ResultInterface {
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += [
+        'InstanceId' => "i-{$this->random->name(32, TRUE)}",
+        'Name' => $this->random->name(32, TRUE),
+      ];
+    }
+    return $this->execute('CreateImage', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
   public function modifyImageAttribute(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ModifyImageAttribute', $params);
   }
 
@@ -577,7 +583,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function modifyTransitGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ModifyTransitGateway', $params);
   }
 
@@ -585,7 +590,10 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createKeyPair(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += ['KeyName' => $this->random->name(32, TRUE)];
+    }
     return $this->execute('CreateKeyPair', $params, $credentials);
   }
 
@@ -593,7 +601,10 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createNetworkInterface(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += ['SubnetId' => "subnet-{$this->random->name(32, TRUE)}"];
+    }
     return $this->execute('CreateNetworkInterface', $params, $credentials);
   }
 
@@ -601,7 +612,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function modifyNetworkInterfaceAttribute(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ModifyNetworkInterfaceAttribute', $params);
   }
 
@@ -609,7 +619,30 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createTags(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
+    if (!empty($params['DryRun']) && count($params) === 1) {
+      $result = $this->describeSecurityGroups(
+        [
+          'DryRun' => FALSE,
+          'GroupNames' => ['default'],
+        ],
+        $credentials
+      );
+      if (empty($result['SecurityGroups'][0]['GroupId'])) {
+        throw new Ec2ServiceException('Failed to test createTags() on getting a required parameter, a Resource ID, by calling describeSecurityGroups().',
+          'describeSecurityGroups', 'UnauthorizedOperation');
+      }
+      $group_id_prepared_by_aws = $result['SecurityGroups'][0]['GroupId'];
+      // Set required parameters if missing.
+      $params += [
+        'Resources' => [$group_id_prepared_by_aws],
+        'Tags' => [
+          [
+            'Key' => 'Name',
+            'Value' => $this->random->name(32, TRUE),
+          ],
+        ],
+      ];
+    }
     return $this->execute('CreateTags', $params, $credentials);
   }
 
@@ -617,39 +650,58 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteTags(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteTags', $params);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createVolume(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateVolume', $params);
+  public function createVolume(array $params = [], array $credentials = []): ?ResultInterface {
+    if (!empty($params['DryRun']) && count($params) === 1) {
+      $availability_zones = $this->getAvailabilityZones();
+      if (empty($availability_zones)) {
+        throw new Ec2ServiceException($this->t('Failed to test createVolume() on getting a required parameter, AvailabilityZone, by calling getAvailabilityZones().'),
+          'createVolume', 'UnauthorizedOperation');
+      }
+      // Set required parameters if missing.
+      $params += [
+        'AvailabilityZone' => array_shift($availability_zones),
+        'Size' => 1024,
+      ];
+    }
+    return $this->execute('CreateVolume', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
   public function modifyVolume(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ModifyVolume', $params);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createSnapshot(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateSnapshot', $params);
+  public function createSnapshot(array $params = [], array $credentials = []): ?ResultInterface {
+    if (!empty($params['DryRun']) && count($params) === 1) {
+      $volumes = $this->describeVolumes([], $credentials);
+      if (empty($volumes['Volumes'][0]['VolumeId'])) {
+        throw new Ec2ServiceException($this->t('Failed to test createSnapshot() on getting a required parameter, VolumeId, by calling describeVolumes().'),
+          'createSnapshot', 'UnauthorizedOperation');
+      }
+      $params['VolumeId'] = $volumes['Volumes'][0]['VolumeId'];
+    }
+    return $this->execute('CreateSnapshot', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
   public function createVpc(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += ['CidrBlock' => '10.0.0.0/8'];
+    }
     return $this->execute('CreateVpc', $params, $credentials);
   }
 
@@ -657,47 +709,45 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createInternetGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('CreateInternetGateway', $params);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createCarrierGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateCarrierGateway', $params);
+  public function createCarrierGateway(array $params = [], array $credentials = []): ?ResultInterface {
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += ['VpcId' => $this->random->name(32, TRUE)];
+    }
+    return $this->execute('CreateCarrierGateway', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createTransitGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateTransitGateway', $params);
+  public function createTransitGateway(array $params = [], array $credentials = []): ?ResultInterface {
+    return $this->execute('CreateTransitGateway', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
   public function createFlowLogs(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('CreateFlowLogs', $params);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createVpcPeeringConnection(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateVpcPeeringConnection', $params);
+  public function createVpcPeeringConnection(array $params = [], array $credentials = []): ?ResultInterface {
+    return $this->execute('CreateVpcPeeringConnection', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
   public function acceptVpcPeeringConnection(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AcceptVpcPeeringConnection', $params);
   }
 
@@ -705,7 +755,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeVpcPeeringConnections(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeVpcPeeringConnections', $params, $credentials);
   }
 
@@ -713,7 +762,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeFlowLogs(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeFlowLogs', $params, $credentials);
   }
 
@@ -721,7 +769,13 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createSecurityGroup(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += [
+        'Description' => $this->random->name(32, TRUE),
+        'GroupName' => $this->random->name(32, TRUE),
+      ];
+    }
     return $this->execute('CreateSecurityGroup', $params, $credentials);
   }
 
@@ -729,26 +783,13 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deregisterImage(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeregisterImage', $params);
   }
 
   /**
-   * Get Regions list from API.
-   *
-   * @param array $params
-   *   The array of API parameters.
-   * @param array $credentials
-   *   The array of credentials.
-   *
-   * @return array
-   *   The array of API result.
-   *
-   * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
-   *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
+   * {@inheritdoc}
    */
   public function describeInstances(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeInstances', $params, $credentials);
   }
 
@@ -756,7 +797,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeInstanceAttribute(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeInstanceAttribute', $params, $credentials);
   }
 
@@ -764,7 +804,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeImages(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeImages', $params, $credentials);
   }
 
@@ -772,7 +811,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeImageAttribute(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeImageAttribute', $params, $credentials);
   }
 
@@ -780,7 +818,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeSecurityGroups(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeSecurityGroups', $params, $credentials);
   }
 
@@ -788,7 +825,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeNetworkInterfaces(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeNetworkInterfaces', $params, $credentials);
   }
 
@@ -796,7 +832,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeAddresses(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeAddresses', $params, $credentials);
   }
 
@@ -804,7 +839,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeSnapshots(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     if (empty($credentials)) {
       $cloud_config = $this->cloudConfigPluginManager->loadConfigEntity();
       $account_id = $cloud_config->get('field_account_id')->value;
@@ -826,7 +860,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeKeyPairs(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeKeyPairs', $params, $credentials);
   }
 
@@ -834,7 +867,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeVolumes(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeVolumes', $params, $credentials);
   }
 
@@ -842,7 +874,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeAvailabilityZones(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeAvailabilityZones', $params, $credentials);
   }
 
@@ -850,7 +881,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeVpcs(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeVpcs', $params, $credentials);
   }
 
@@ -858,7 +888,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeInternetGateways(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeInternetGateways', $params, $credentials);
   }
 
@@ -866,7 +895,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeCarrierGateways(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeCarrierGateways', $params, $credentials);
   }
 
@@ -874,7 +902,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeTransitGateways(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeTransitGateways', $params, $credentials);
   }
 
@@ -882,7 +909,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeTransitGatewayRouteTables(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeTransitGatewayRouteTables', $params);
   }
 
@@ -890,7 +916,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function associateVpcCidrBlock(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AssociateVpcCidrBlock', $params);
   }
 
@@ -898,7 +923,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function disassociateVpcCidrBlock(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DisassociateVpcCidrBlock', $params);
   }
 
@@ -906,16 +930,21 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeSubnets(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeSubnets', $params, $credentials);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function createSubnet(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
-    return $this->execute('CreateSubnet', $params);
+  public function createSubnet(array $params = [], array $credentials = []): ?ResultInterface {
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += [
+        'CidrBlock' => '10.0.0.0/8',
+        'VpcId' => $this->random->name(32, TRUE),
+      ];
+    }
+    return $this->execute('CreateSubnet', $params, $credentials);
   }
 
   /**
@@ -954,7 +983,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function importKeyPair(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ImportKeyPair', $params);
   }
 
@@ -962,7 +990,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function terminateInstance(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('TerminateInstances', $params);
   }
 
@@ -970,7 +997,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteSecurityGroup(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteSecurityGroup', $params);
   }
 
@@ -978,7 +1004,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteNetworkInterface(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteNetworkInterface', $params);
   }
 
@@ -986,7 +1011,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function disassociateAddress(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DisassociateAddress', $params);
   }
 
@@ -994,7 +1018,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function releaseAddress(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ReleaseAddress', $params);
   }
 
@@ -1002,7 +1025,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteKeyPair(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteKeyPair', $params);
   }
 
@@ -1010,7 +1032,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteVolume(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteVolume', $params);
   }
 
@@ -1018,7 +1039,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function attachVolume(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AttachVolume', $params);
   }
 
@@ -1026,7 +1046,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function detachVolume(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DetachVolume', $params);
   }
 
@@ -1034,7 +1053,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteSnapshot(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteSnapshot', $params);
   }
 
@@ -1042,7 +1060,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteVpc(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteVpc', $params);
   }
 
@@ -1050,7 +1067,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteInternetGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteInternetGateway', $params);
   }
 
@@ -1058,7 +1074,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function attachInternetGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('AttachInternetGateway', $params);
   }
 
@@ -1066,7 +1081,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function detachInternetGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DetachInternetGateway', $params);
   }
 
@@ -1074,7 +1088,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteCarrierGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteCarrierGateway', $params);
   }
 
@@ -1082,7 +1095,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteTransitGateway(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteTransitGateway', $params);
   }
 
@@ -1090,7 +1102,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteVpcPeeringConnection(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteVpcPeeringConnection', $params);
   }
 
@@ -1098,7 +1109,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteFlowLogs(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteFlowLogs', $params);
   }
 
@@ -1106,7 +1116,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteSubnet(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteSubnet', $params);
   }
 
@@ -1114,7 +1123,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function revokeSecurityGroupIngress(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('RevokeSecurityGroupIngress', $params, $credentials);
   }
 
@@ -1122,7 +1130,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function revokeSecurityGroupEgress(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('RevokeSecurityGroupEgress', $params, $credentials);
   }
 
@@ -1130,7 +1137,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function runInstances(array $params = [], array $tags = [], string $bundle = 'aws_cloud') {
-    $params += $this->getDefaultParameters();
     $uid_key_name = $this->cloudService->getTagCreatedByUid(
       $bundle,
       $this->cloudContext,
@@ -1174,7 +1180,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function stopInstances(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('StopInstances', $params);
   }
 
@@ -1182,7 +1187,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function startInstances(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('StartInstances', $params);
   }
 
@@ -1190,7 +1194,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function modifyInstanceAttribute(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ModifyInstanceAttribute', $params);
   }
 
@@ -1198,7 +1201,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function rebootInstances(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('RebootInstances', $params);
   }
 
@@ -1206,7 +1208,13 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createLaunchTemplate(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
+    if (!empty($params['DryRun'])) {
+      // Set required parameters if missing.
+      $params += [
+        'LaunchTemplateName' => $this->random->name(32, TRUE),
+        'LaunchTemplateData' => [],
+      ];
+    }
     return $this->execute('CreateLaunchTemplate', $params);
   }
 
@@ -1214,7 +1222,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function modifyLaunchTemplate(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('ModifyLaunchTemplate', $params);
   }
 
@@ -1222,7 +1229,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteLaunchTemplate(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteLaunchTemplate', $params);
   }
 
@@ -1230,7 +1236,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeLaunchTemplates(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeLaunchTemplates', $params, $credentials);
   }
 
@@ -1238,7 +1243,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function createLaunchTemplateVersion(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('CreateLaunchTemplateVersion', $params);
   }
 
@@ -1246,7 +1250,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function deleteLaunchTemplateVersions(array $params = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DeleteLaunchTemplateVersions', $params);
   }
 
@@ -1254,7 +1257,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function describeLaunchTemplateVersions(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('DescribeLaunchTemplateVersions', $params, $credentials);
   }
 
@@ -3638,7 +3640,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
    * {@inheritdoc}
    */
   public function getConsoleOutput(array $params = [], array $credentials = []): ?ResultInterface {
-    $params += $this->getDefaultParameters();
     return $this->execute('GetConsoleOutput', $params, $credentials);
   }
 
@@ -3669,16 +3670,6 @@ class Ec2Service extends CloudServiceBase implements Ec2ServiceInterface {
     return time();
   }
 
-  /**
-   * Setup the default parameters that all API calls will need.
-   *
-   * @return array
-   *   Array of default parameters.
-   */
-  protected function getDefaultParameters() {
-    return [];
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceException.php b/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceException.php
index d47e563bdf063dd4dc26035258e5d3b741add647..2acb97ac578b39caea01c5332b43f467fb03ff9e 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceException.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceException.php
@@ -2,9 +2,35 @@
 
 namespace Drupal\aws_cloud\Service\Ec2;
 
+use Aws\Command;
+use Aws\Ec2\Exception\Ec2Exception;
+
 /**
  * AWS Cloud EC2 Service Exception.
  */
-class Ec2ServiceException extends \Exception {
+class Ec2ServiceException extends Ec2Exception {
+
+  /**
+   * Ec2ServiceException constructor.
+   *
+   * @param string $message
+   *   Exception message.
+   * @param string $command_name
+   *   Aws command name.
+   * @param string|null $error_code
+   *   Aws error code to be set in the context.
+   * @param array $context
+   *   Exception context.
+   * @param \Drupal\aws_cloud\Service\Ec2\Exception|null $previous
+   *   The previous exception.
+   */
+  public function __construct(string $message, $command_name = 'Unknown', string $error_code = NULL, array $context = [], Exception $previous = NULL) {
+
+    $command = new Command(ucfirst($command_name));
+    if (!empty($error_code)) {
+      $context['code'] = $error_code;
+    }
+    parent::__construct($message, $command, $context, $previous);
+  }
 
 }
diff --git a/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceInterface.php b/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceInterface.php
index 606c5b16ec104a01808ff40f4ba988d44619fd8b..7089ceb6ad1b40096927810094a2bad8018d8124 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceInterface.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Service/Ec2/Ec2ServiceInterface.php
@@ -10,6 +10,67 @@ use Drupal\cloud\Entity\CloudConfigInterface;
  */
 interface Ec2ServiceInterface {
 
+  /**
+   * AWS error code indicating permission granted.
+   *
+   * @FIXME share with S3 Service.
+   *
+   * @var string
+   */
+  public const DRY_RUN_OPERATION = 'DryRunOperation';
+
+  /**
+   * AWS error codes for permission failure.
+   *
+   * @FIXME Move to AWS common service level to share with other services,
+   * i.e., S3 Service.
+   *
+   * @var string[]
+   * @see https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html
+   */
+  public const PERMISSION_ERROR_CODES = [
+    'AuthFailure',
+    'Blocked',
+    'OptInRequired',
+    'PendingVerification',
+    'UnauthorizedOperation',
+    'ValidationError',
+  ];
+
+  /**
+   * Mapping from Drupal permission to AWS API.
+   *
+   * @var string[]
+   */
+  public const PERMISSION_TO_AWS_API = [
+    'add aws cloud elastic ip' => 'AllocateAddress',
+    'add aws cloud carrier gateway' => 'CreateCarrierGateway',
+    'add aws cloud image' => 'CreateImage',
+    'add aws cloud internet gateway' => 'CreateInternetGateway',
+    'add aws cloud key pair' => 'CreateKeyPair',
+    'add aws cloud network interface' => 'CreateNetworkInterface',
+    'add aws cloud snapshot' => 'CreateSnapshot',
+    'add aws cloud security group' => ['CreateSecurityGroup', 'CreateVpc'],
+    'add aws cloud subnet' => 'CreateSubnet',
+    'add aws cloud transit gateway' => 'CreateTransitGateway',
+    'add aws cloud vpc' => 'CreateVpc',
+    'add aws cloud vpc peering connection' => 'CreateVpcPeeringConnection',
+    'add aws cloud volume' => 'CreateVolume',
+    // @See https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-launch-template-permissions.html#policy-example-create-launch-template
+    'add cloud server templates' => [
+      'CreateLaunchTemplate',
+      'CreateTags',
+      'DescribeAvailabilityZones',
+      'DescribeImages',
+      'DescribeKeyPairs',
+      'DescribeNetworkInterfaces',
+      'DescribeSecurityGroups',
+      'DescribeSubnets',
+      'DescribeVpcs',
+    ],
+    'list cloud server template' => 'DescribeLaunchTemplates',
+  ];
+
   /**
    * Set the cloud context.
    *
@@ -166,7 +227,7 @@ interface Ec2ServiceInterface {
    *   Array of credentials.
    *
    * @return \Aws\ResultInterface
-   *   Result or NULL if there is an error.
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
@@ -182,7 +243,7 @@ interface Ec2ServiceInterface {
    *   Array of credentials.
    *
    * @return \Aws\ResultInterface
-   *   Result or NULL if there is an error.
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
@@ -202,14 +263,16 @@ interface Ec2ServiceInterface {
    *
    * @param array $params
    *   Parameters array to send to API.
+   * @param array $credentials
+   *   Array of credentials.
    *
-   * @return array
-   *   Array of Volume or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
    */
-  public function createVolume(array $params = []): ?ResultInterface;
+  public function createVolume(array $params = [], array $credentials = []): ?ResultInterface;
 
   /**
    * Calls the Amazon EC2 API endpoint Modify Volume.
@@ -230,14 +293,16 @@ interface Ec2ServiceInterface {
    *
    * @param array $params
    *   Parameters array to send to API.
+   * @param array $credentials
+   *   Array of credentials.
    *
-   * @return array
-   *   Array of Snapshot or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
    */
-  public function createSnapshot(array $params = []): ?ResultInterface;
+  public function createSnapshot(array $params = [], array $credentials = []): ?ResultInterface;
 
   /**
    * Calls the Amazon EC2 API endpoint Create Vpc.
@@ -248,7 +313,7 @@ interface Ec2ServiceInterface {
    *   Array of credentials.
    *
    * @return \Aws\ResultInterface
-   *   Result or NULL if there is an error.
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
@@ -274,28 +339,32 @@ interface Ec2ServiceInterface {
    *
    * @param array $params
    *   Parameters array to send to API.
+   * @param array $credentials
+   *   Array of credentials.
    *
-   * @return array
-   *   Array of Carrier Gateway or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
    */
-  public function createCarrierGateway(array $params = []): ?ResultInterface;
+  public function createCarrierGateway(array $params = [], array $credentials = []): ?ResultInterface;
 
   /**
    * Calls the Amazon EC2 API endpoint Create Transit Gateway.
    *
    * @param array $params
    *   Parameters array to send to API.
+   * @param array $credentials
+   *   Array of credentials.
    *
-   * @return array
-   *   Array of Transit Gateway or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
    */
-  public function createTransitGateway(array $params = []): ?ResultInterface;
+  public function createTransitGateway(array $params = [], array $credentials = []): ?ResultInterface;
 
   /**
    * Calls the Amazon EC2 API endpoint Create Flow logs.
@@ -316,14 +385,16 @@ interface Ec2ServiceInterface {
    *
    * @param array $params
    *   Parameters array to send to API.
+   * @param array $credentials
+   *   Array of credentials.
    *
-   * @return array
-   *   Array of VPC or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
    */
-  public function createVpcPeeringConnection(array $params = []): ?ResultInterface;
+  public function createVpcPeeringConnection(array $params = [], array $credentials = []): ?ResultInterface;
 
   /**
    * Calls the Amazon EC2 API endpoint Accept VPC Peering Connection.
@@ -380,7 +451,7 @@ interface Ec2ServiceInterface {
    *   Array of credentials.
    *
    * @return \Aws\ResultInterface
-   *   Result or NULL if there is an error.
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
@@ -396,7 +467,7 @@ interface Ec2ServiceInterface {
    *   Array of credentials.
    *
    * @return \Aws\ResultInterface
-   *   Result or NULL if there is an error.
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
@@ -746,14 +817,16 @@ interface Ec2ServiceInterface {
    *
    * @param array $params
    *   Parameters array to send to API.
+   * @param array $credentials
+   *   Array of credentials.
    *
-   * @return array
-   *   Array of Subnets or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Ec2\Ec2ServiceException
    *   If the $params is empty or $ec2_client (Ec2Client) is NULL.
    */
-  public function createSubnet(array $params = []): ?ResultInterface;
+  public function createSubnet(array $params = [], array $credentials = []): ?ResultInterface;
 
   /**
    * Get regions.
diff --git a/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamService.php b/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamService.php
index 988ddd57f5e9208fbf469b4c58ae93ee9117829d..5283d99e99d831b3024fe5891e2f94df7b668080 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamService.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamService.php
@@ -105,8 +105,8 @@ class IamService extends CloudServiceBase implements IamServiceInterface {
    * @param bool $show_errors
    *   Show IAM errors.
    *
-   * @return array
-   *   Array of execution result or NULL if there is an error.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    *
    * @throws \Drupal\aws_cloud\Service\Iam\IamServiceException
    *   If the $iam_client (IamClient) is NULL.
@@ -139,6 +139,14 @@ class IamService extends CloudServiceBase implements IamServiceInterface {
       ]);
     }
     catch (IamException $e) {
+      // IAM permission validation needs AwsException to be thrown as it is
+      // determined by the error code of the exception, 'AccessDenied'.
+      // Note: IAM permission itself doesn't support DryRun param, but our code
+      // passes it as a marker.
+      if (!empty($params['DryRun'])) {
+        throw $e;
+      }
+
       if ($show_errors === TRUE) {
         $this->messenger->addError($this->t('Error: The operation "@operation" could not be performed.', [
           '@operation' => $operation,
diff --git a/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamServiceInterface.php b/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamServiceInterface.php
index 1344df1d75c2d1558c504fd526bd8564fa755442..35e97cf9fea520a0b4204b3fecbd4d3f0dc1c037 100644
--- a/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamServiceInterface.php
+++ b/modules/cloud_service_providers/aws_cloud/src/Service/Iam/IamServiceInterface.php
@@ -10,6 +10,33 @@ use Aws\ResultInterface;
  */
 interface IamServiceInterface {
 
+  /**
+   * AWS error codes for permission failure.
+   *
+   * @FIXME Move to AWS common service level to share with other services,
+   * i.e., S3 Service.
+   *
+   * @var string[]
+   */
+  public const PERMISSION_ERROR_CODES = [
+    'AccessDenied',
+    'IncompleteSignature',
+    'InvalidAuthenticationCode',
+    'InvalidCertificate',
+    'InvalidPublicKey',
+    'KeyPairMismatch',
+    'MalformedCertificate',
+  ];
+
+  /**
+   * Mapping from Drupal permission to AWS API.
+   *
+   * @var string[]
+   */
+  public const PERMISSION_TO_AWS_API = [
+    'add cloud server templates' => 'ListInstanceProfiles',
+  ];
+
   /**
    * Set the cloud context.
    *
@@ -39,8 +66,8 @@ interface IamServiceInterface {
    * @param bool $show_errors
    *   Show IAM errors.
    *
-   * @return array
-   *   Instance profiles.
+   * @return \Aws\ResultInterface
+   *   Result object or NULL if there is an error.
    */
   public function listInstanceProfiles(array $params = [], array $credentials = [], $show_errors = TRUE): ?ResultInterface;
 
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ElasticIpTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ElasticIpTest.yml
index 84ec909ae399f6a2bc8ceb2c8065ab5ee4c85ac5..98fc9ef9d6031f3a8b4408e468107ff285e7c22f 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ElasticIpTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ElasticIpTest.yml
@@ -4,6 +4,7 @@ AllocateAddress:
   AllocationId: '{{allocation_id}}'
   Domain: '{{domain}}'
   NetworkBorderGroup: us-west-2
+  ErrorCode: '{{error_code}}'
 
 # For Elastic IP.
 DescribeAddresses:
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ImageTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ImageTest.yml
index 30d16cf69bff470db8f66c26404a6b8b19466a4e..23e8cf62850296b7e25cb334ec7aef88ae86ee6e 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ImageTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/ImageTest.yml
@@ -4,6 +4,7 @@ CreateImage:
   Tags:
     - Key: 'aws_cloud_image_{{uid_tag_key}}'
       Value: '{{uid}}'
+  ErrorCode: '{{error_code}}'
 
 DescribeImages:
   Images:
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/InstanceTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/InstanceTest.yml
index 3bc2d8f6f4dc0e3ec4b306e733de94c10a7b8738..6d8501d390e258e0f33ca84dcff33609a4025f32 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/InstanceTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/InstanceTest.yml
@@ -12,28 +12,45 @@ TerminateInstances:
     - InstanceId: '{{instance_id}}'
 
 DescribeSecurityGroups:
-  SecurityGroups: []
+  SecurityGroups:
+  -
+    GroupId: '{{security_group_id}}'
+    GroupName: '{{security_group_name}}'
+    Description: '{{description}}'
+    VpcId: '{{vpc_id}}'
+    OwnerId: '{{account_id}}'
+  ErrorCode: '{{error_code}}'
 DescribeKeyPairs:
   KeyPairs: []
+  ErrorCode: '{{error_code}}'
 DescribeAddresses:
   Addresses: []
 DescribeNetworkInterfaces:
   NetworkInterfaces: []
+  ErrorCode: '{{error_code}}'
 DescribeSnapshots:
   Snapshots: []
 DescribeVolumes:
   Volumes: []
 DescribeVpcs:
   Vpcs: []
+  ErrorCode: '{{error_code}}'
 DescribeSubnets:
   Subnets: []
+  ErrorCode: '{{error_code}}'
 
 CreateLaunchTemplate:
   LaunchTemplate: []
+  ErrorCode: '{{error_code}}'
+CreateTags:
+  ErrorCode: '{{error_code}}'
+
 DeleteLaunchTemplate:
   LaunchTemplate: []
+
 DescribeLaunchTemplates:
   LaunchTemplates: []
+  ErrorCode: '{{error_code}}'
 
 DescribeImages:
   Images:
@@ -56,3 +73,8 @@ DescribeImages:
       Public: '{{public}}'
       State: '{{state}}'
       CreationDate: '{{creation_date}}'
+  ErrorCode: '{{error_code}}'
+
+ListInstanceProfiles:
+  instanceProfiles: []
+  ErrorCode: '{{iam_error_code}}'
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/KeyPairTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/KeyPairTest.yml
index 0ed2f17087afb7a00a18c6e36bdf0692d884888c..06680d362a80fc1f731acdc6f479db2fb9cef10a 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/KeyPairTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/KeyPairTest.yml
@@ -3,3 +3,4 @@ CreateKeyPair:
   KeyPairId: '{{key_pair_id}}'
   KeyFingerprint: '{{key_fingerprint}}'
   KeyMaterial: '{{key_material}}'
+  ErrorCode: '{{error_code}}'
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/NetworkInterfaceTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/NetworkInterfaceTest.yml
index d96282f3a0e855c50d003d44d445c9770e4b19df..a36ade9fecc147e6b9200cb7e3db1322b89180cf 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/NetworkInterfaceTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/NetworkInterfaceTest.yml
@@ -3,3 +3,4 @@ CreateNetworkInterface:
     NetworkInterfaceId: '{{network_interface_id}}'
     Status: pending
     VpcId: '{{vpc_id}}'
+  ErrorCode: '{{error_code}}'
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SecurityGroupTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SecurityGroupTest.yml
index 026296327cdaa11c27993b1bfd083c8747d51c9b..002f87497eaca84e517ed2b3b2c722b4cf0d11a8 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SecurityGroupTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SecurityGroupTest.yml
@@ -4,8 +4,11 @@ DescribeVpcs:
       VpcId: '{{vpc_id}}'
       CidrBlock: '{{cidr_block}}'
       IsDefault: true
+
 CreateSecurityGroup:
   GroupId: '{{group_id}}'
+  ErrorCode: '{{error_code}}'
+
 DescribeSecurityGroups:
   SecurityGroups:
     -
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SnapshotTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SnapshotTest.yml
index 13a4a42d4295893d820eb07dcf404ec53028080e..32c9598e45c24b38c7ef0b30aab7e39a3e116fa4 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SnapshotTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/SnapshotTest.yml
@@ -3,3 +3,8 @@ CreateSnapshot:
   Status: pending
   StartTime: '{{start_time}}'
   Encrypted: TRUE
+  ErrorCode: '{{error_code}}'
+
+DescribeVolumes:
+  Volumes:
+    - VolumeId: '{{volume_id}}'
\ No newline at end of file
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/VolumeTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/VolumeTest.yml
index f07eb180a7299b80c3f546dbc54c07f0d928e1aa..6bf9ccbbe89e831055533a892c95f126bd2a35cb 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/VolumeTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Ec2/VolumeTest.yml
@@ -5,7 +5,10 @@ CreateVolume:
   Tags:
     - Key: 'aws_cloud_volume_{{uid_tag_key}}'
       Value: '{{uid}}'
+  ErrorCode: '{{error_code}}'
 
 DescribeVolumes:
   Volumes: []
   Attachments: []
+
+# Don't mock DescribeAvailabilityZones here as it's set by AwsCloudTestBase.yml
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/CarrierGatewayTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/CarrierGatewayTest.yml
index a942bca035596f0dc8b9fe5869f047442de1da14..935adc40f5658d66df3e33e4c33eaed0a6aafd3e 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/CarrierGatewayTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/CarrierGatewayTest.yml
@@ -1,3 +1,4 @@
 CreateCarrierGateway:
   CarrierGateway:
     CarrierGatewayId: '{{carrier_gateway_id}}'
+  ErrorCode: '{{error_code}}'
\ No newline at end of file
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/InternetGatewayTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/InternetGatewayTest.yml
index 7e8c27a5077c65c933e46c8d5a78cc9b4f3b0fd0..5f146217913912ab142bf59e92e20af5fdd743cb 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/InternetGatewayTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/InternetGatewayTest.yml
@@ -1,3 +1,4 @@
 CreateInternetGateway:
   InternetGateway:
     InternetGatewayId: '{{internet_gateway_id}}'
+  ErrorCode: '{{error_code}}'
\ No newline at end of file
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/SubnetTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/SubnetTest.yml
index 01cad5eb7306d5a95594c6094a0d7999f77f0784..a8a6f84cb6982269829e61780be9ed0586139b61 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/SubnetTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/SubnetTest.yml
@@ -1,3 +1,5 @@
 CreateSubnet:
   Subnet:
     SubnetId: '{{subnet_id}}'
+  ErrorCode: '{{error_code}}'
+
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/TransitGatewayTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/TransitGatewayTest.yml
index e27b331cfe7ff8ba5b4a18978a277ce619bed3a2..8587f89e7d1b163cde24424c9040a917e6332f4f 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/TransitGatewayTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/TransitGatewayTest.yml
@@ -1,6 +1,7 @@
 CreateTransitGateway:
   TransitGateway:
     TransitGatewayId: '{{transit_gateway_id}}'
+  ErrorCode: '{{error_code}}'
 
 DescribeTransitGatewayRouteTables:
   TransitGatewayRouteTables:
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcPeeringConnectionTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcPeeringConnectionTest.yml
index 68d9e696bffc790b7802d28e446c67b0690d9a9b..e820b5021618bcbc05541945cf362b13236fa474 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcPeeringConnectionTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcPeeringConnectionTest.yml
@@ -1,6 +1,8 @@
 CreateVpcPeeringConnection:
   VpcPeeringConnection:
     VpcPeeringConnectionId: '{{vpc_peering_connection_id}}'
+  ErrorCode: '{{error_code}}'
+
 AcceptVpcPeeringConnection:
   VpcPeeringConnection:
     VpcPeeringConnectionId: '{{vpc_peering_connection_id}}'
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcTest.yml
index bda06d38d32bd4b885dae07d4205a6e97b60c432..cd3e54ba6a1bdbbde448bab89bd3bf3308c2567e 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/Vpc/VpcTest.yml
@@ -3,3 +3,4 @@ CreateVpc:
     VpcId: '{{vpc_id}}'
 # DescribeVpcs:
 #   Vpcs: []
+  ErrorCode: '{{error_code}}'
\ No newline at end of file
diff --git a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/cloud/server_template/CloudServerTemplateTest.yml b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/cloud/server_template/CloudServerTemplateTest.yml
index a48f3b56728d0bb151e937ca57f672ec5bc6a884..c7834e4aea752c0a9ffd3fad7ed9ad7b68689c0b 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/cloud/server_template/CloudServerTemplateTest.yml
+++ b/modules/cloud_service_providers/aws_cloud/tests/mock_data/Functional/cloud/server_template/CloudServerTemplateTest.yml
@@ -1,6 +1,7 @@
 CreateLaunchTemplate:
   LaunchTemplate:
     LatestVersionNumber: 1
+  ErrorCode: '{{error_code}}'
 
 DeleteLaunchTemplate:
   LaunchTemplate: []
@@ -13,3 +14,42 @@ DeleteLaunchTemplateVersions:
   SuccessfullyDeletedLaunchTemplateVersions:
     - LaunchTemplateName: template1
       VersionNumber: 1
+
+# Imports from InstanceTest.yml
+DescribeSecurityGroups:
+  SecurityGroups:
+    -
+      GroupId: '{{security_group_id}}'
+      GroupName: '{{security_group_name}}'
+  ErrorCode: '{{error_code}}'
+DescribeKeyPairs:
+  KeyPairs: []
+  ErrorCode: '{{error_code}}'
+DescribeAddresses:
+  Addresses: []
+DescribeNetworkInterfaces:
+  NetworkInterfaces: []
+  ErrorCode: '{{error_code}}'
+DescribeSnapshots:
+  Snapshots: []
+DescribeVolumes:
+  Volumes: []
+DescribeVpcs:
+  Vpcs: []
+  ErrorCode: '{{error_code}}'
+DescribeSubnets:
+  Subnets: []
+  ErrorCode: '{{error_code}}'
+
+CreateTags:
+  ErrorCode: '{{error_code}}'
+
+DescribeLaunchTemplates:
+  ErrorCode: '{{error_code}}'
+
+DescribeImages:
+  ErrorCode: '{{error_code}}'
+
+ListInstanceProfiles:
+  instanceProfiles: []
+  ErrorCode: '{{iam_error_code}}'
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ElasticIpTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ElasticIpTest.php
index e7a04c2a9d3999db32329dbee1b3e2068614388b..286c69905d1e7ab1fbf6832fcdd46f92e6e64f85 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ElasticIpTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ElasticIpTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 
 use Drupal\aws_cloud\Entity\Ec2\Instance;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\aws_cloud\Entity\Ec2\NetworkInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 use Drupal\Tests\cloud\Functional\Utils;
@@ -15,6 +16,7 @@ use Drupal\Tests\cloud\Functional\Utils;
 class ElasticIpTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_ELASTIC_IP_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_ELASTIC_IP_ADD_BUTTON = 'Add AWS Cloud Elastic IP';
 
   /**
    * {@inheritdoc}
@@ -39,6 +41,7 @@ class ElasticIpTest extends AwsCloudTestBase {
       'public_ip' => Utils::getRandomPublicIp(),
       'allocation_id' => 'eipalloc-' . $this->getRandomId(),
       'domain' => 'vpc',
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
 
       // For Instance.
       'instance_id' => 'i-' . $this->getRandomId(),
@@ -68,6 +71,7 @@ class ElasticIpTest extends AwsCloudTestBase {
     // List Elastic IP for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/elastic_ip");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_ELASTIC_IP_ADD_BUTTON);
 
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/elastic_ip/add");
 
@@ -734,4 +738,22 @@ class ElasticIpTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testElasticIpAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_ELASTIC_IP_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['AllocateAddress']);
+      // List Elastic IP for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/elastic_ip");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_ELASTIC_IP_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/elastic_ip/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ImageTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ImageTest.php
index 1306d1fae81078e2523f23a5e348b83091e978ea..284d5e08605a7a3bba5788fd44a2b95a607e2f8c 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ImageTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/ImageTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 
 use Drupal\aws_cloud\Entity\Ec2\Image;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -13,8 +14,9 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class ImageTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_IMAGE_REPEAT_COUNT = 2;
-
   public const AWS_UPDATE_IMAGE_LIST_REFRESH_TIME_ADJUSTMENT = 10 * 60;
+  public const AWS_CLOUD_IMAGE_ADD_BUTTON = 'Add AWS Cloud Image';
+  public const AWS_CLOUD_IMAGE_IMPORT_BUTTON = 'Import AWS Cloud Image';
 
   /**
    * {@inheritdoc}
@@ -60,6 +62,7 @@ class ImageTest extends AwsCloudTestBase {
       'hypervisor' => $hypervisor[array_rand($hypervisor)],
       'public' => $public[array_rand($public)],
       'uid' => !empty($this->webUser) ? $this->webUser->id() : 0,
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -89,6 +92,8 @@ class ImageTest extends AwsCloudTestBase {
     $this->clickLink($this->t('Refresh'));
     $this->assertSession()->pageTextContains($this->t('Updated Images.'));
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_IMAGE_ADD_BUTTON);
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_IMAGE_IMPORT_BUTTON);
 
     // Register a new Image.
     $add = $this->createImageTestFormData(self::AWS_CLOUD_IMAGE_REPEAT_COUNT);
@@ -703,4 +708,29 @@ class ImageTest extends AwsCloudTestBase {
     $this->assertSession()->pageTextContains(strip_tags($this->t('The @type @label has been deleted.', $t_args)));
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testImageAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_IMAGE_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateImage']);
+      if (random_int(0, 1) === 1) {
+        $this->updateErrorCodeMockData(['DescribeImages']);
+      }
+      // List Image for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/image");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_IMAGE_ADD_BUTTON);
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_IMAGE_IMPORT_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/image/add");
+      $this->assertAccessDenied();
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/images/import");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/InstanceTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/InstanceTest.php
index 2a9eb6c77e9a6ddb86793bfbf2e52f2c7b382982..b5dc5624462ce78b5ec3ce02ab578130b789506f 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/InstanceTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/InstanceTest.php
@@ -5,6 +5,8 @@ namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 use Drupal\aws_cloud\Entity\Ec2\Image;
 use Drupal\aws_cloud\Entity\Ec2\Instance;
 use Drupal\aws_cloud\Entity\Ec2\NetworkInterface;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
+use Drupal\aws_cloud\Service\Iam\IamServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 use Drupal\Tests\cloud\Functional\Utils;
 
@@ -19,6 +21,8 @@ class InstanceTest extends AwsCloudTestBase {
    * Create three Instances for a test case.
    */
   public const AWS_CLOUD_INSTANCE_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_INSTANCE_ADD_BUTTON = 'Add | Launch AWS Cloud Instance';
+  public const AWS_CLOUD_LAUNCH_TEMPLATE_ADD_BUTTON = 'Add launch template';
 
   /**
    * {@inheritdoc}
@@ -39,6 +43,7 @@ class InstanceTest extends AwsCloudTestBase {
       'launch cloud server template',
       'approve launch aws cloud instance',
       'launch approved cloud server template',
+      'add cloud server templates',
 
       'add aws cloud image',
       'list aws cloud image',
@@ -76,7 +81,7 @@ class InstanceTest extends AwsCloudTestBase {
       'affinity' => $this->random->name(8, TRUE),
       'launch_time' => date('c'),
       'security_group_id' => 'sg-' . $this->getRandomId(),
-      'security_group_name' => $this->random->name(10, TRUE),
+      'security_group_name' => 'default',
       'public_dns_name' => Utils::getPublicDns($region, $public_ip),
       'public_ip_address' => $public_ip,
       'private_dns_name' => Utils::getPrivateDns($region, $private_ip),
@@ -101,6 +106,7 @@ class InstanceTest extends AwsCloudTestBase {
       'image_type' => $image_type[array_rand($image_type)],
       'hypervisor' => $hypervisor[array_rand($hypervisor)],
       'public' => $public[array_rand($public)],
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -123,6 +129,7 @@ class InstanceTest extends AwsCloudTestBase {
     // List Instance for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/${cloud_context}/instance");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_INSTANCE_ADD_BUTTON);
 
     // Launch a new Instance.
     $add = $this->createInstanceTestFormData(self::AWS_CLOUD_INSTANCE_REPEAT_COUNT);
@@ -145,6 +152,7 @@ class InstanceTest extends AwsCloudTestBase {
       $this->drupalGet("/clouds/design/server_template/${cloud_context}");
       $this->assertNoErrorMessage();
       $this->assertSession()->pageTextContains($server_template->name->value);
+      $this->assertSession()->pageTextContains(self::AWS_CLOUD_LAUNCH_TEMPLATE_ADD_BUTTON);
 
       $this->addInstanceMockData(InstanceTest::class, $add[$i]['name'], $add[$i]['key_pair_name'], $regions, 'running', '', $cloud_context);
       $this->drupalGet("/clouds/design/server_template/${cloud_context}/{$server_template->id()}/launch");
@@ -1093,4 +1101,48 @@ class InstanceTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testInstanceAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_INSTANCE_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['DescribeLaunchTemplates']);
+      // List Instance for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/${cloud_context}/instance");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_INSTANCE_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/design/server_template/${cloud_context}");
+      $this->assertAccessDenied();
+    }
+
+    $perm = 'add cloud server templates';
+
+    for ($i = 0; $i < self::AWS_CLOUD_INSTANCE_REPEAT_COUNT; $i++) {
+      $this->reloadMockData();
+
+      $this->drupalGet("/clouds/design/server_template/${cloud_context}");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextContains(self::AWS_CLOUD_LAUNCH_TEMPLATE_ADD_BUTTON);
+
+      random_int(0, 1) === 1
+        ? $this->updateErrorCodeMockData(
+          [
+            Ec2ServiceInterface::PERMISSION_TO_AWS_API[$perm][array_rand(Ec2ServiceInterface::PERMISSION_TO_AWS_API[$perm], 1)],
+          ]
+        )
+        : $this->updateErrorCodeMockData(
+          [
+            IamServiceInterface::PERMISSION_TO_AWS_API[$perm],
+          ],
+          IamServiceInterface::PERMISSION_ERROR_CODES[array_rand(IamServiceInterface::PERMISSION_ERROR_CODES, 1)]
+        );
+
+      $this->drupalGet("/clouds/design/server_template/${cloud_context}/aws_cloud/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/KeyPairTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/KeyPairTest.php
index 96f62a41434a7021ef7339acde01a8efd6ba00f1..3a22f304e3438fb3c61b91ac19899e0a024e80a4 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/KeyPairTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/KeyPairTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 
 use Drupal\aws_cloud\Entity\Ec2\KeyPair;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -13,6 +14,8 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class KeyPairTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_KEY_PAIR_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_KEY_PAIR_ADD_BUTTON = 'Add AWS Cloud Key Pair';
+  public const AWS_CLOUD_KEY_PAIR_IMPORT_BUTTON = 'Import AWS Cloud Key Pair';
 
   /**
    * {@inheritdoc}
@@ -45,6 +48,7 @@ class KeyPairTest extends AwsCloudTestBase {
       'key_pair_id' => 'key-' . $this->getRandomId(),
       'key_fingerprint' => implode(':', $key_fingerprint_parts),
       'key_material' => $key_material,
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -63,6 +67,8 @@ class KeyPairTest extends AwsCloudTestBase {
     // List Key Pair for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/key_pair");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_KEY_PAIR_ADD_BUTTON);
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_KEY_PAIR_IMPORT_BUTTON);
 
     // Add a new Key Pair.
     $add = $this->createKeyPairTestFormData(self::AWS_CLOUD_KEY_PAIR_REPEAT_COUNT);
@@ -385,7 +391,28 @@ class KeyPairTest extends AwsCloudTestBase {
     for ($i = 0; $i < self::AWS_CLOUD_KEY_PAIR_REPEAT_COUNT; $i++) {
       $this->assertSession()->pageTextNotContains($add[$i]['key_pair_name']);
     }
+  }
+
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testKeyPairAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_KEY_PAIR_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateKeyPair']);
+      // List Key Pairs for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/key_pair");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_KEY_PAIR_ADD_BUTTON);
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_KEY_PAIR_IMPORT_BUTTON);
 
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/key_pair/add");
+      $this->assertAccessDenied();
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/key_pair/import");
+      $this->assertAccessDenied();
+    }
   }
 
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/NetworkInterfaceTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/NetworkInterfaceTest.php
index 964eb467b5f62e2b8aaf4be7c56ad67d0350c9a1..942cd9dcce87e8f3bd29cf1128d22f06d0030245 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/NetworkInterfaceTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/NetworkInterfaceTest.php
@@ -4,6 +4,7 @@ namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 
 use Drupal\aws_cloud\Entity\Ec2\NetworkInterface;
 use Drupal\aws_cloud\Entity\Ec2\SecurityGroup;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -14,6 +15,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class NetworkInterfaceTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_NETWORK_INTERFACE_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_NETWORK_INTERFACE_ADD_BUTTON = 'Add AWS Cloud Network interface';
 
   /**
    * {@inheritdoc}
@@ -36,6 +38,7 @@ class NetworkInterfaceTest extends AwsCloudTestBase {
     return [
       'network_interface_id' => 'eni-' . $this->getRandomId(),
       'vpc_id' => 'vpc-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -55,6 +58,7 @@ class NetworkInterfaceTest extends AwsCloudTestBase {
     // List Network Interface for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/network_interface");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_NETWORK_INTERFACE_ADD_BUTTON);
 
     // Create security groups.
     $security_groups = $this->createSecurityGroupRandomTestFormData();
@@ -495,4 +499,22 @@ class NetworkInterfaceTest extends AwsCloudTestBase {
 
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testNetworkInterfaceAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_NETWORK_INTERFACE_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateNetworkInterface']);
+      // List Network Interface for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/network_interface");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_NETWORK_INTERFACE_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/network_interface/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SecurityGroupTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SecurityGroupTest.php
index 0585051cecf5f173fc5dff975d9a5d3cf983c222..5c1354cbc96396350d35d45d0dbc2d612ffc8414 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SecurityGroupTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SecurityGroupTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 
 use Drupal\aws_cloud\Entity\Ec2\SecurityGroup;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 use Drupal\Tests\cloud\Functional\Utils;
 
@@ -13,6 +14,8 @@ use Drupal\Tests\cloud\Functional\Utils;
  */
 class SecurityGroupTest extends AwsCloudTestBase {
 
+  public const AWS_CLOUD_SECURITY_GROUP_ADD_BUTTON = 'Add AWS Cloud Security Group';
+
   /**
    * {@inheritdoc}
    */
@@ -38,6 +41,7 @@ class SecurityGroupTest extends AwsCloudTestBase {
       'cidr_block' => Utils::getRandomCidr(),
       'group_id' => 'sg-' . $this->getRandomId(),
       'group_name' => $this->random->name(8, TRUE),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -56,6 +60,7 @@ class SecurityGroupTest extends AwsCloudTestBase {
     // List Security Group for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/security_group");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_SECURITY_GROUP_ADD_BUTTON);
 
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/security_group/add");
     $this->assertSession()->pageTextContains($this->t('You do not have any VPCs. You need a VPC in order to create a security group. You can create a VPC.'));
@@ -901,4 +906,22 @@ class SecurityGroupTest extends AwsCloudTestBase {
     return $permissions[$source];
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testSecurityGroupAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::$awsCloudSecurityGroupRepeatCount; $i++) {
+      $this->updateErrorCodeMockData(['CreateSecurityGroup']);
+      // List Security Group for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/security_Group");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_SECURITY_GROUP_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/security_Group/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SnapshotTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SnapshotTest.php
index 6d0619f69699e32d9519932b987868fef4e88a69..e55266f33c4d48ea91cc036943050e1607483810 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SnapshotTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/SnapshotTest.php
@@ -4,6 +4,7 @@ namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 
 use Drupal\aws_cloud\Entity\Ec2\Volume;
 use Drupal\aws_cloud\Entity\Ec2\Snapshot;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 use Drupal\Tests\cloud\Functional\Utils;
 
@@ -15,6 +16,7 @@ use Drupal\Tests\cloud\Functional\Utils;
 class SnapshotTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_SNAPSHOT_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_SNAPSHOT_ADD_BUTTON = 'Add AWS Cloud Snapshot';
 
   /**
    * {@inheritdoc}
@@ -44,6 +46,8 @@ class SnapshotTest extends AwsCloudTestBase {
       'cidr_block' => Utils::getRandomCidr(),
       'group_id' => 'sg-' . $this->getRandomId(),
       'start_time' => date('c'),
+      'volume_id' => 'vol-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -64,6 +68,7 @@ class SnapshotTest extends AwsCloudTestBase {
     // List Snapshot for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/snapshot");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_SNAPSHOT_ADD_BUTTON);
 
     // Create random volumes.
     $volumes = $this->createVolumesRandomTestFormData();
@@ -661,4 +666,25 @@ class SnapshotTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testSnapshotAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_SNAPSHOT_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateSnapshot']);
+      if (random_int(0, 1) === 1) {
+        $this->updateErrorCodeMockData(['DescribeVolumes']);
+      }
+      // List Snapshot for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/snapshot");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_SNAPSHOT_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/snapshot/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/VolumeTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/VolumeTest.php
index 1f1f0a08caeb2132dce10ae446310839586fcfe8..f896dbc7bc5e7474570cd7efd17556b43d7f497b 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/VolumeTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Ec2/VolumeTest.php
@@ -5,6 +5,7 @@ namespace Drupal\Tests\aws_cloud\Functional\Ec2;
 use Drupal\aws_cloud\Entity\Ec2\Instance;
 use Drupal\aws_cloud\Entity\Ec2\Snapshot;
 use Drupal\aws_cloud\Entity\Ec2\Volume;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 use Drupal\Tests\cloud\Functional\Utils;
 
@@ -16,6 +17,7 @@ use Drupal\Tests\cloud\Functional\Utils;
 class VolumeTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_VOLUME_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_VOLUME_ADD_BUTTON = 'Add AWS Cloud Volume';
 
   /**
    * {@inheritdoc}
@@ -43,6 +45,8 @@ class VolumeTest extends AwsCloudTestBase {
       'volume_id' => 'vol-' . $this->getRandomId(),
       'create_time' => date('c'),
       'uid' => !empty($this->webUser) ? $this->webUser->id() : 0,
+      'cloud_context' => $this->cloudContext,
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -59,6 +63,7 @@ class VolumeTest extends AwsCloudTestBase {
     // List Volume for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/volume");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_VOLUME_ADD_BUTTON);
 
     // Add a new Volume.
     $delete_count = 0;
@@ -627,4 +632,25 @@ class VolumeTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testVolumeAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_VOLUME_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateVolume']);
+      if (random_int(0, 1) === 1) {
+        $this->updateErrorCodeMockData(['DescribeAvailabilityZones']);
+      }
+      // List Volume for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/volume");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_VOLUME_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/volume/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/CarrierGatewayTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/CarrierGatewayTest.php
index ef1ec6127abb7bdf49af9f4017d9efa63f9228b7..cfb80bb0a8b771c36611237a74d979cddf4da167 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/CarrierGatewayTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/CarrierGatewayTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\Vpc;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -12,6 +13,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class CarrierGatewayTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_CARRIER_GATEWAY_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_CARRIER_GATEWAY_ADD_BUTTON = 'Add AWS Cloud Carrier gateway';
 
   /**
    * {@inheritdoc}
@@ -33,6 +35,7 @@ class CarrierGatewayTest extends AwsCloudTestBase {
   protected function getMockDataTemplateVars(): array {
     return [
       'carrier_gateway_id' => 'igw-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -369,4 +372,22 @@ class CarrierGatewayTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testCarrierGatewayAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_CARRIER_GATEWAY_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateCarrierGateway']);
+      // List Carrier Gateway for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/carrier_gateway");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_CARRIER_GATEWAY_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/carrier_gateway/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/InternetGatewayTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/InternetGatewayTest.php
index 468f203286299160e05fc4d1d5e9032e2fd134a8..958a01627b9c2ba0d65854c400cfa5634c4c159a 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/InternetGatewayTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/InternetGatewayTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\Vpc;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -12,6 +13,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class InternetGatewayTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_INTERNET_GATEWAY_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_INTERNET_GATEWAY_ADD_BUTTON = 'Add AWS Cloud Internet Gateway';
 
   /**
    * {@inheritdoc}
@@ -33,6 +35,7 @@ class InternetGatewayTest extends AwsCloudTestBase {
   protected function getMockDataTemplateVars(): array {
     return [
       'internet_gateway_id' => 'igw-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -49,6 +52,7 @@ class InternetGatewayTest extends AwsCloudTestBase {
     // List Internet Gateway for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/internet_gateway");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_INTERNET_GATEWAY_ADD_BUTTON);
 
     // Add a new Internet Gateway.
     $add = $this->createInternetGatewayTestFormData(self::AWS_CLOUD_INTERNET_GATEWAY_REPEAT_COUNT);
@@ -363,4 +367,22 @@ class InternetGatewayTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testInternetGatewayAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_INTERNET_GATEWAY_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateInternetGateway']);
+      // List Internet Gateway for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/internet_gateway");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_INTERNET_GATEWAY_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/internet_gateway/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/SubnetTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/SubnetTest.php
index a08e8bae9fc64dd5107a0f6632cb19aa1c389d61..766a040dd82829e94e93d778964069f335bf5432 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/SubnetTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/SubnetTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\Vpc;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -12,6 +13,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class SubnetTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_SUBNET_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_SUBNET_ADD_BUTTON = 'Add AWS Cloud Subnet';
 
   /**
    * {@inheritdoc}
@@ -33,6 +35,7 @@ class SubnetTest extends AwsCloudTestBase {
   protected function getMockDataTemplateVars(): array {
     return [
       'subnet_id' => 'subnet-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -47,6 +50,7 @@ class SubnetTest extends AwsCloudTestBase {
     // List Subnet for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/subnet");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_SUBNET_ADD_BUTTON);
 
     $vpc_ids = $this->updateVpcsMockData(self::AWS_CLOUD_SUBNET_REPEAT_COUNT);
 
@@ -372,4 +376,22 @@ class SubnetTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testSubnetAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_SUBNET_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateSubnet']);
+      // List Subnet for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/subnet");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_SUBNET_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/subnet/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/TransitGatewayTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/TransitGatewayTest.php
index 84404670fd9571ff6fb5121bc9b45cdd4593c547..67ad233a60c61b5770766f10c39a384b706d1b00 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/TransitGatewayTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/TransitGatewayTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\Vpc;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -12,6 +13,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class TransitGatewayTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_TRANSIT_GATEWAY_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_TRANSIT_GATEWAY_ADD_BUTTON = 'Add AWS Cloud Transit Gateway';
 
   /**
    * {@inheritdoc}
@@ -34,6 +36,7 @@ class TransitGatewayTest extends AwsCloudTestBase {
     return [
       'transit_gateway_id' => 'igw-' . $this->getRandomId(),
       'transit_gateway_route_table_id' => 'tgw-rtb-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -50,6 +53,7 @@ class TransitGatewayTest extends AwsCloudTestBase {
     // List Transit Gateway for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/transit_gateway");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_TRANSIT_GATEWAY_ADD_BUTTON);
 
     $vpc_ids = $this->updateVpcsMockData(self::AWS_CLOUD_TRANSIT_GATEWAY_REPEAT_COUNT);
 
@@ -363,4 +367,22 @@ class TransitGatewayTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testTransitGatewayAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_TRANSIT_GATEWAY_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateTransitGateway']);
+      // List Transit Gateway for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/transit_gateway");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_TRANSIT_GATEWAY_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/transit_gateway/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcPeeringConnectionTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcPeeringConnectionTest.php
index 85be46785deee3250f0fcd9d1c54b7640b0b9e4e..7c1d6e6bfe6bb918fd853c379ddf313c5b704ce2 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcPeeringConnectionTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcPeeringConnectionTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\Vpc;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -12,6 +13,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class VpcPeeringConnectionTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_VPC_PEERING_CONNECTION_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_VPC_PEERING_CONNECTION_ADD_BUTTON = 'Add AWS Cloud VPC Peering Connection';
 
   /**
    * {@inheritdoc}
@@ -33,6 +35,7 @@ class VpcPeeringConnectionTest extends AwsCloudTestBase {
   protected function getMockDataTemplateVars(): array {
     return [
       'vpc_peering_connection_id' => 'pcx' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -48,6 +51,7 @@ class VpcPeeringConnectionTest extends AwsCloudTestBase {
     // List VPC Peering Connection for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/vpc_peering_connection");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_VPC_PEERING_CONNECTION_ADD_BUTTON);
 
     $vpc_ids = $this->updateVpcsMockData(self::AWS_CLOUD_VPC_PEERING_CONNECTION_REPEAT_COUNT);
 
@@ -403,4 +407,22 @@ class VpcPeeringConnectionTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testVpcPeeringConnectionAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_VPC_PEERING_CONNECTION_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateVpcPeeringConnection']);
+      // List VPC peering connection for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/vpc_peering_connection");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_VPC_PEERING_CONNECTION_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/vpc_peering_connection/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcTest.php
index b16ab6f3686e3532b63c8a055c27e8196a736b97..ed891e90845c72a06660cd63b4ac3415e15f9a82 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/Vpc/VpcTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\Vpc;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 
 /**
@@ -12,6 +13,7 @@ use Drupal\Tests\aws_cloud\Functional\AwsCloudTestBase;
 class VpcTest extends AwsCloudTestBase {
 
   public const AWS_CLOUD_VPC_REPEAT_COUNT = 2;
+  public const AWS_CLOUD_VPC_ADD_BUTTON = 'Add AWS Cloud VPC';
 
   /**
    * {@inheritdoc}
@@ -33,6 +35,7 @@ class VpcTest extends AwsCloudTestBase {
   protected function getMockDataTemplateVars(): array {
     return [
       'vpc_id' => 'vpc-' . $this->getRandomId(),
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -49,6 +52,7 @@ class VpcTest extends AwsCloudTestBase {
     // List VPC for Amazon EC2.
     $this->drupalGet("/clouds/aws_cloud/$cloud_context/vpc");
     $this->assertNoErrorMessage();
+    $this->assertSession()->pageTextContains(self::AWS_CLOUD_VPC_ADD_BUTTON);
 
     // Add a new Vpc.
     $add = $this->createVpcTestFormData(self::AWS_CLOUD_VPC_REPEAT_COUNT);
@@ -364,4 +368,22 @@ class VpcTest extends AwsCloudTestBase {
     }
   }
 
+  /**
+   * Tests hiding buttons based on access control.
+   */
+  public function testVpcAccessControl(): void {
+    $cloud_context = $this->cloudContext;
+
+    for ($i = 0; $i < self::AWS_CLOUD_VPC_REPEAT_COUNT; $i++) {
+      $this->updateErrorCodeMockData(['CreateVpc']);
+      // List VPC for Amazon EC2.
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/vpc");
+      $this->assertNoErrorMessage();
+      $this->assertSession()->pageTextNotContains(self::AWS_CLOUD_VPC_ADD_BUTTON);
+
+      $this->drupalGet("/clouds/aws_cloud/$cloud_context/vpc/add");
+      $this->assertAccessDenied();
+    }
+  }
+
 }
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigPermissionTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigPermissionTest.php
index da4bf731be7617dcd990bfb8a53ae52f9b7efc02..93e2ce8caf5ef2470b800d77aee9a14a654f277b 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigPermissionTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigPermissionTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Functional\cloud\config;
 
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\cloud\Entity\CloudContentEntityBase;
 use Drupal\Tests\aws_cloud\Traits\AwsCloudTestFormDataTrait;
 use Drupal\Tests\aws_cloud\Traits\AwsCloudTestMockTrait;
@@ -217,7 +218,7 @@ class AwsCloudConfigPermissionTest extends CloudConfigTestBase {
   protected function getMockDataTemplateVars(): array {
     return [
       'group_id'    => 'sg-' . $this->getRandomId(),
-      'error_code'  => 'DryRunOperation',
+      'error_code'  => Ec2ServiceInterface::DRY_RUN_OPERATION,
     ];
   }
 
@@ -349,7 +350,7 @@ class AwsCloudConfigPermissionTest extends CloudConfigTestBase {
       $this->setUpDetailsBeforeSave($i, $add, $target_region_index);
 
       // Set all required IAM permissions.
-      $this->setAwsCloudConfigPermissionMockData($this->flattenPermissions());
+      $this->updateErrorCodeMockData($this->flattenPermissions(), Ec2ServiceInterface::DRY_RUN_OPERATION);
       // For error-expected testing, unset randomly-picked IAM permissions.
       $unset_mandatory_perm = array_rand($this->getPermissionsToValidate()['mandatory']);
       $unset_optional_perm = array_rand($this->getPermissionsToValidate()['optional']);
@@ -398,7 +399,7 @@ class AwsCloudConfigPermissionTest extends CloudConfigTestBase {
     $label = "{$add[$repeat_index]['name[0][value]']} {$target_region_display_name}";
 
     // To avoid DryRunOperation AwdException, empty the error code.
-    $this->setAwsCloudConfigPermissionMockData($this->flattenPermissions(), '');
+    $this->updateErrorCodeMockData($this->flattenPermissions(), '');
     // Make sure no error message on showing an add form.
     $this->drupalGet('/admin/structure/cloud_config/add');
     $this->assertNoErrorMessage();
@@ -430,7 +431,7 @@ class AwsCloudConfigPermissionTest extends CloudConfigTestBase {
     for ($i = 0, $num = 2; $i < self::AWS_CLOUD_CONFIG_REPEAT_COUNT; $i++) {
 
       // Set all required IAM permissions.
-      $this->setAwsCloudConfigPermissionMockData($this->flattenPermissions());
+      $this->updateErrorCodeMockData($this->flattenPermissions(), Ec2ServiceInterface::DRY_RUN_OPERATION);
       // For error-expected testing, unset randomly-picked IAM permissions.
       $unset_mandatory_perm = array_rand($this->getPermissionsToValidate()['mandatory']);
       $unset_optional_perm = array_rand($this->getPermissionsToValidate()['optional']);
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigTest.php
index e34e40027dfbb8f95d4cf49c5bc48319d147c3f0..3922de1f6a4140f6c8c8f60c30a8750ca2189bb0 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/config/AwsCloudConfigTest.php
@@ -133,10 +133,6 @@ class AwsCloudConfigTest extends CloudConfigTestBase {
       $this->cloudConfig->delete();
     }
 
-    $this->drupalPlaceBlock('system_menu_block:main', [
-      'region' => 'header',
-      'theme' => 'claro',
-    ]);
   }
 
   /**
@@ -396,6 +392,12 @@ class AwsCloudConfigTest extends CloudConfigTestBase {
    * Tests AWS menu based on cloud service provider.
    */
   public function testAwsMenu(): void {
+
+    $this->drupalPlaceBlock('system_menu_block:main', [
+      'region' => 'header',
+      'theme' => 'claro',
+    ]);
+
     // List AWS Cloud service providers for Amazon EC2.
     $this->drupalGet('/admin/structure/cloud_config');
     $this->assertNoErrorMessage();
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/server_template/CloudServerTemplateTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/server_template/CloudServerTemplateTest.php
index c21839e44df57344ce0a7d4f74e6f3816abe17a5..010f913e38506e51edbac9a80bc82b905f93f2c0 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/server_template/CloudServerTemplateTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Functional/cloud/server_template/CloudServerTemplateTest.php
@@ -5,6 +5,7 @@ namespace Drupal\Tests\aws_cloud\Functional\cloud\server_template;
 use Drupal\aws_cloud\Entity\Ec2\Image;
 use Drupal\aws_cloud\Entity\Ec2\KeyPair;
 use Drupal\aws_cloud\Entity\Ec2\SecurityGroup;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\cloud\Entity\CloudContentEntityBase;
 use Drupal\cloud\Entity\CloudServerTemplate;
 use Drupal\cloud\Entity\CloudServerTemplateInterface;
@@ -90,6 +91,17 @@ class CloudServerTemplateTest extends AwsCloudTestBase {
 
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getMockDataTemplateVars(): array {
+    return [
+      'security_group_id' => 'sg-' . $this->getRandomId(),
+      'security_group_name' => 'default',
+      'error_code' => Ec2ServiceInterface::DRY_RUN_OPERATION,
+    ];
+  }
+
   /**
    * Create cloud context.
    *
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Traits/AwsCloudTestMockTrait.php b/modules/cloud_service_providers/aws_cloud/tests/src/Traits/AwsCloudTestMockTrait.php
index ab167452605b1f16c4e7129d17649a7e1fce14a9..95b8e2aa5ef56bb7a0956dda235c6d598bac887b 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Traits/AwsCloudTestMockTrait.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Traits/AwsCloudTestMockTrait.php
@@ -6,6 +6,7 @@ use Drupal\aws_cloud\Entity\Ec2\Instance;
 use Drupal\Component\Serialization\Yaml;
 use Drupal\gapps\Service\GoogleSpreadsheetService;
 use Drupal\Tests\cloud\Functional\Utils;
+use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface;
 use Drupal\Tests\aws_cloud\Functional\Ec2\ImageTest;
 
 /**
@@ -1866,19 +1867,27 @@ trait AwsCloudTestMockTrait {
   }
 
   /**
-   * Set Aws Cloud Config Permission mock data with given error code.
+   * Update Aws error code mock data.
    *
    * @param array $commands
    *   Array of commands to update mocked result.
-   * @param string $error_code
-   *   An error code to set.
+   * @param string|null $error_code
+   *   An error code to set. If not specified, a random permission error is set.
+   *   If an empty string is set, it can suppress AwsException in mockHandler.
    */
-  protected function setAwsCloudConfigPermissionMockData(array $commands = [], string $error_code = 'DryRunOperation'): void {
+  protected function updateErrorCodeMockData(array $commands = [], string $error_code = NULL): void {
 
     $mock_data = $this->getMockDataFromConfig();
     foreach ($commands as $command) {
       if (!empty($mock_data[$command])) {
-        $mock_data[$command]['ErrorCode'] = $error_code;
+        // This $error_code is used for AwsException error code.
+        // If $error_code is NULL, a random permission error code is set.
+        // If $error_code is an empty string, set an empty string NOT to throw
+        // AwsException in mockHandler.
+        $mock_data[$command]['ErrorCode'] = $error_code
+          ?? Ec2ServiceInterface::PERMISSION_ERROR_CODES[array_rand(
+            Ec2ServiceInterface::PERMISSION_ERROR_CODES
+          )];
       }
     }
     $this->updateMockDataToConfig($mock_data);
diff --git a/modules/cloud_service_providers/aws_cloud/tests/src/Unit/Plugin/cloud/server_template/AwsCloudServerTemplatePluginTest.php b/modules/cloud_service_providers/aws_cloud/tests/src/Unit/Plugin/cloud/server_template/AwsCloudServerTemplatePluginTest.php
index 0559d5b5abf2178996cfb90ec9935aeb423bf193..3c5389ccefa9b7a7d85871e373e62575799ff686 100644
--- a/modules/cloud_service_providers/aws_cloud/tests/src/Unit/Plugin/cloud/server_template/AwsCloudServerTemplatePluginTest.php
+++ b/modules/cloud_service_providers/aws_cloud/tests/src/Unit/Plugin/cloud/server_template/AwsCloudServerTemplatePluginTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\aws_cloud\Unit\Plugin\cloud\server_template;
 
+use Drupal\aws_cloud\Access\AwsCloudAccessInterface;
 use Drupal\aws_cloud\Entity\Ec2\ImageInterface;
 use Drupal\aws_cloud\Entity\Ec2\KeyPairInterface;
 use Drupal\aws_cloud\Entity\Ec2\NetworkInterfaceInterface;
@@ -125,6 +126,7 @@ class AwsCloudServerTemplatePluginTest extends UnitTestCase {
     $mock_entity_link_renderer = $this->createMock(EntityLinkRendererInterface::class);
     $mock_route_match = $this->createMock(RouteMatchInterface::class);
     $mock_cloud_service = $this->createMock(CloudServiceInterface::class);
+    $mock_aws_cloud_access = $this->createMock(AwsCloudAccessInterface::class);
 
     $this->plugin = new AwsCloudServerTemplatePlugin(
       [], '', [],
@@ -136,7 +138,8 @@ class AwsCloudServerTemplatePluginTest extends UnitTestCase {
       $mock_cloud_config_plugin_manager,
       $mock_entity_link_renderer,
       $mock_route_match,
-      $mock_cloud_service
+      $mock_cloud_service,
+      $mock_aws_cloud_access,
     );
 
     $this->random = new Random();
diff --git a/modules/cloud_service_providers/k8s/src/Plugin/cloud/config/K8sCloudConfigPlugin.php b/modules/cloud_service_providers/k8s/src/Plugin/cloud/config/K8sCloudConfigPlugin.php
index 0f010a78f1acc4022704258d5a3e1e1b621345c6..f2de2a08c507ec2ede8690c78a63ca045b6a40be 100644
--- a/modules/cloud_service_providers/k8s/src/Plugin/cloud/config/K8sCloudConfigPlugin.php
+++ b/modules/cloud_service_providers/k8s/src/Plugin/cloud/config/K8sCloudConfigPlugin.php
@@ -4,11 +4,15 @@ namespace Drupal\k8s\Plugin\cloud\config;
 
 use Drupal\cloud\Plugin\cloud\CloudPluginBase;
 use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\File\FileSystem;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\k8s\Entity\K8sEntityInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * Kubernetes cloud service provider plugin.
@@ -141,4 +145,11 @@ class K8sCloudConfigPlugin extends CloudPluginBase implements CloudConfigPluginI
     return K8sEntityInterface::ANNOTATION_CREATED_BY_UID;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/modules/cloud_service_providers/k8s/src/Plugin/cloud/server_template/K8sCloudServerTemplatePlugin.php b/modules/cloud_service_providers/k8s/src/Plugin/cloud/server_template/K8sCloudServerTemplatePlugin.php
index 5897c3912ee6c61093039be63df28e9fdfe8cbfc..14a346db8961cbb658959e3190671f5d7c5e24f3 100644
--- a/modules/cloud_service_providers/k8s/src/Plugin/cloud/server_template/K8sCloudServerTemplatePlugin.php
+++ b/modules/cloud_service_providers/k8s/src/Plugin/cloud/server_template/K8sCloudServerTemplatePlugin.php
@@ -12,6 +12,8 @@ use Drupal\Component\Serialization\Yaml;
 use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\Element\EntityAutocomplete;
 use Drupal\Core\Entity\EntityMalformedException;
@@ -22,6 +24,7 @@ use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Template\TwigEnvironment;
 use Drupal\k8s\Entity\K8sEntityInterface;
 use Drupal\k8s\Entity\K8sNamespace;
@@ -30,6 +33,7 @@ use Drupal\k8s\Service\K8sServiceException;
 use Drupal\k8s\Service\K8sServiceInterface;
 use Drupal\k8s\Traits\K8sFormTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 use Drupal\k8s\Plugin\EntityReferenceSelection\LaunchTemplateUserSelection;
 use Drupal\user\Entity\User;
 use GuzzleHttp\Promise\Promise;
@@ -1311,4 +1315,11 @@ class K8sCloudServerTemplatePlugin extends CloudPluginBase implements CloudServe
     return $leftovers;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/modules/cloud_service_providers/openstack/src/Plugin/cloud/config/OpenStackCloudConfigPlugin.php b/modules/cloud_service_providers/openstack/src/Plugin/cloud/config/OpenStackCloudConfigPlugin.php
index 692c9cfcfce2450c33bca0396c5c775111894119..1048144d8156f0d6e89d880c0e6bcbc9e9c2b449 100644
--- a/modules/cloud_service_providers/openstack/src/Plugin/cloud/config/OpenStackCloudConfigPlugin.php
+++ b/modules/cloud_service_providers/openstack/src/Plugin/cloud/config/OpenStackCloudConfigPlugin.php
@@ -4,6 +4,10 @@ namespace Drupal\openstack\Plugin\cloud\config;
 
 use Drupal\aws_cloud\Plugin\cloud\config\AwsCloudConfigPlugin;
 use Drupal\openstack\Entity\OpenStackEntityInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * OpenStack cloud service provider (CloudConfig) plugin class.
@@ -74,4 +78,11 @@ class OpenStackCloudConfigPlugin extends AwsCloudConfigPlugin {
     return OpenStackEntityInterface::TAG_CREATED_BY_UID;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/modules/cloud_service_providers/openstack/src/Plugin/cloud/server_template/OpenStackServerTemplatePlugin.php b/modules/cloud_service_providers/openstack/src/Plugin/cloud/server_template/OpenStackServerTemplatePlugin.php
index de0f5dc0167dc22add61e42ac39612e38e4d9a63..ff583bae3e93a07e86f7bb39bedfcfc4be15c2d4 100644
--- a/modules/cloud_service_providers/openstack/src/Plugin/cloud/server_template/OpenStackServerTemplatePlugin.php
+++ b/modules/cloud_service_providers/openstack/src/Plugin/cloud/server_template/OpenStackServerTemplatePlugin.php
@@ -15,13 +15,17 @@ use Drupal\cloud\Plugin\cloud\server_template\CloudServerTemplatePluginInterface
 use Drupal\cloud\Service\EntityLinkRendererInterface;
 use Drupal\cloud\Service\Util\EntityLinkWithShortNameHtmlGenerator;
 use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * OpenStack cloud launch template plugin.
@@ -628,4 +632,11 @@ class OpenStackServerTemplatePlugin extends CloudPluginBase implements CloudServ
     return $prefix;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/modules/cloud_service_providers/terraform/src/Plugin/cloud/config/TerraformCloudConfigPlugin.php b/modules/cloud_service_providers/terraform/src/Plugin/cloud/config/TerraformCloudConfigPlugin.php
index aa8a25ba1817e06bb776abe65e878c73e413098e..977218659c6e2d83a466899ab29a513f48d98a5c 100644
--- a/modules/cloud_service_providers/terraform/src/Plugin/cloud/config/TerraformCloudConfigPlugin.php
+++ b/modules/cloud_service_providers/terraform/src/Plugin/cloud/config/TerraformCloudConfigPlugin.php
@@ -5,10 +5,14 @@ namespace Drupal\terraform\Plugin\cloud\config;
 use Drupal\cloud\Entity\CloudConfig;
 use Drupal\cloud\Plugin\cloud\CloudPluginBase;
 use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\File\FileSystem;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * Terraform cloud service provider plugin.
@@ -141,4 +145,11 @@ class TerraformCloudConfigPlugin extends CloudPluginBase implements CloudConfigP
     return '';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/modules/cloud_service_providers/vmware/src/Plugin/cloud/config/VmwareCloudConfigPlugin.php b/modules/cloud_service_providers/vmware/src/Plugin/cloud/config/VmwareCloudConfigPlugin.php
index e5d654073087446ec4328a159d9440b0015e8987..9883ceb2c30cdc0d1f15e0d9cb4989d6139de525 100644
--- a/modules/cloud_service_providers/vmware/src/Plugin/cloud/config/VmwareCloudConfigPlugin.php
+++ b/modules/cloud_service_providers/vmware/src/Plugin/cloud/config/VmwareCloudConfigPlugin.php
@@ -5,10 +5,14 @@ namespace Drupal\vmware\Plugin\cloud\config;
 use Drupal\cloud\Entity\CloudConfig;
 use Drupal\cloud\Plugin\cloud\CloudPluginBase;
 use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\File\FileSystem;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * VMware cloud service provider plugin.
@@ -142,4 +146,11 @@ class VmwareCloudConfigPlugin extends CloudPluginBase implements CloudConfigPlug
     return '';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/modules/cloud_service_providers/vmware/src/Plugin/cloud/server_template/VmwareCloudServerTemplatePlugin.php b/modules/cloud_service_providers/vmware/src/Plugin/cloud/server_template/VmwareCloudServerTemplatePlugin.php
index df3f2071ff4e1aad08004ed72301384085e7f71a..2b29be949bc581afc1cb86b21eab1c87f54d5364 100644
--- a/modules/cloud_service_providers/vmware/src/Plugin/cloud/server_template/VmwareCloudServerTemplatePlugin.php
+++ b/modules/cloud_service_providers/vmware/src/Plugin/cloud/server_template/VmwareCloudServerTemplatePlugin.php
@@ -11,6 +11,8 @@ use Drupal\cloud\Service\CloudServiceInterface;
 use Drupal\cloud\Service\EntityLinkRendererInterface;
 use Drupal\cloud\Traits\CloudContentEntityTrait;
 use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityMalformedException;
 use Drupal\Core\Entity\EntityStorageException;
@@ -18,11 +20,13 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\vmware\Service\VmwareServiceException;
 use Drupal\vmware\Service\VmwareService;
 use Drupal\vmware\Service\VmwareServiceInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * VMware Cloud launch template plugin.
@@ -371,4 +375,11 @@ class VmwareCloudServerTemplatePlugin extends CloudPluginBase implements CloudSe
     return $field;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return AccessResult::allowed();
+  }
+
 }
diff --git a/src/Controller/CloudConfigController.php b/src/Controller/CloudConfigController.php
index 31d08557ca3f7dd1a4266af635872b6368abace9..c91fb201c79cde19c887a3d6466502089f142971 100644
--- a/src/Controller/CloudConfigController.php
+++ b/src/Controller/CloudConfigController.php
@@ -3,8 +3,11 @@
 namespace Drupal\cloud\Controller;
 
 use Drupal\cloud\Entity\CloudConfigInterface;
+use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManagerInterface;
+use Drupal\cloud\Traits\CloudContentEntityTrait;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
@@ -23,6 +26,8 @@ use Symfony\Component\Routing\Route;
  */
 class CloudConfigController extends ControllerBase implements ContainerInjectionInterface {
 
+  use CloudContentEntityTrait;
+
   /**
    * The route match.
    *
@@ -44,6 +49,13 @@ class CloudConfigController extends ControllerBase implements ContainerInjection
    */
   protected $dateFormatter;
 
+  /**
+   * The cloud config plugin manager.
+   *
+   * @var \Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManager
+   */
+  protected $cloudConfigPluginManager;
+
   /**
    * Constructs an OperationsController object.
    *
@@ -53,15 +65,19 @@ class CloudConfigController extends ControllerBase implements ContainerInjection
    *   The render service.
    * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
    *   The date formatter service.
+   * @param \Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManagerInterface $cloud_config_plugin_manager
+   *   The cloud config plugin manager.
    */
   public function __construct(
     RouteMatchInterface $route_match,
     RendererInterface $renderer,
-    DateFormatterInterface $date_formatter) {
+    DateFormatterInterface $date_formatter,
+    CloudConfigPluginManagerInterface $cloud_config_plugin_manager) {
 
     $this->routeMatch = $route_match;
     $this->renderer = $renderer;
     $this->dateFormatter = $date_formatter;
+    $this->cloudConfigPluginManager = $cloud_config_plugin_manager;
   }
 
   /**
@@ -71,7 +87,8 @@ class CloudConfigController extends ControllerBase implements ContainerInjection
     return new static(
       $container->get('current_route_match'),
       $container->get('renderer'),
-      $container->get('date.formatter')
+      $container->get('date.formatter'),
+      $container->get('plugin.manager.cloud_config_plugin')
     );
   }
 
@@ -265,40 +282,51 @@ class CloudConfigController extends ControllerBase implements ContainerInjection
    * @param \Symfony\Component\Routing\Route $route
    *   The route object.
    *
-   * @return \Drupal\Core\Access\AccessResult
+   * @return \Drupal\Core\Access\AccessResultInterface
    *   The access result.
    */
-  public function access($cloud_context, AccountInterface $account, Route $route) {
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    // @FIXME: Change the validation order to be local Drupal permission first.
+    // Validating the API permissions of a cloud service provider, e.g., AWS IAM
+    // permissions.
+    $access_result = $this->cloudConfigPluginManager->access($cloud_context, $account, $route);
+
+    // Validation of the local Drupal permissions.
     $perm = $route->getOption('perm');
     if (strpos($perm, '+') === FALSE && strpos($perm, ',') === FALSE) {
       if ($account->hasPermission('view all cloud service providers')) {
         return AccessResult::allowedIfHasPermissions($account, [
           $perm,
-        ]);
+        ])
+          ->andIf($access_result);
       }
       else {
         return AccessResult::allowedIfHasPermissions($account, [
           $perm,
           'view ' . $cloud_context,
-        ]);
+        ])
+          ->andIf($access_result);
       }
     }
     else {
       if (!$account->hasPermission('view all cloud service providers')
         && !$account->hasPermission('view ' . $cloud_context)) {
 
-        return AccessResult::neutral();
+        return AccessResult::neutral()
+          ->andIf($access_result);
       }
 
       // Allow to conjunct the permissions with OR ('+') or AND (',').
       $split = explode(',', $perm);
       // Support AND permission check.
       if (count($split) > 1) {
-        return AccessResult::allowedIfHasPermissions($account, $split, 'AND');
+        return AccessResult::allowedIfHasPermissions($account, $split, 'AND')
+          ->andIf($access_result);
       }
       else {
         $split = explode('+', $perm);
-        return AccessResult::allowedIfHasPermissions($account, $split, 'OR');
+        return AccessResult::allowedIfHasPermissions($account, $split, 'OR')
+          ->andIf($access_result);
       }
     }
   }
diff --git a/src/Controller/CloudServerTemplateController.php b/src/Controller/CloudServerTemplateController.php
index 9bd57e66948d8d1936f2411e2f46659653edbbf0..d465c7699c6b404bb779fb34dcc961874dd2e2af 100644
--- a/src/Controller/CloudServerTemplateController.php
+++ b/src/Controller/CloudServerTemplateController.php
@@ -6,6 +6,7 @@ use Drupal\cloud\Entity\CloudServerTemplateInterface;
 use Drupal\cloud\Plugin\cloud\server_template\CloudServerTemplatePluginManagerInterface;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
@@ -408,25 +409,34 @@ class CloudServerTemplateController extends ControllerBase implements ContainerI
    * @param \Symfony\Component\Routing\Route $route
    *   The route object.
    *
-   * @return \Drupal\Core\Access\AccessResult
+   * @return \Drupal\Core\Access\AccessResultInterface
    *   The access result.
    */
-  public function access($cloud_context, AccountInterface $account, Route $route) {
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    // @FIXME: Change the validation order to be local Drupal permission first.
+    // Validating the API permissions of a cloud service provider, e.g., AWS IAM
+    // permissions.
+    $access_result = $this->serverTemplatePluginManager->access($cloud_context, $account, $route);
+
+    // Validation of the local Drupal permissions.
     $perm = $route->getOption('perm');
     if (!$account->hasPermission('view all cloud service providers')
       && !$account->hasPermission('view ' . $cloud_context)) {
-      return AccessResult::neutral();
+      return AccessResult::neutral()
+        ->andIf($access_result);
     }
 
     // Allow to conjunct the permissions with OR ('+') or AND (',').
     $split = explode(',', $perm);
     // Support AND permission check.
     if (count($split) > 1) {
-      return AccessResult::allowedIfHasPermissions($account, $split, 'AND');
+      return AccessResult::allowedIfHasPermissions($account, $split, 'AND')
+        ->andIf($access_result);
     }
     else {
       $split = explode('+', $perm);
-      return AccessResult::allowedIfHasPermissions($account, $split, 'OR');
+      return AccessResult::allowedIfHasPermissions($account, $split, 'OR')
+        ->andIf($access_result);
     }
 
   }
diff --git a/src/Plugin/cloud/config/CloudConfigPluginInterface.php b/src/Plugin/cloud/config/CloudConfigPluginInterface.php
index 98684f7c165cd6988caf489e38c67220d56e792a..a0c76ab656aee006960816d06795fbca2ebc84b9 100644
--- a/src/Plugin/cloud/config/CloudConfigPluginInterface.php
+++ b/src/Plugin/cloud/config/CloudConfigPluginInterface.php
@@ -2,6 +2,10 @@
 
 namespace Drupal\cloud\Plugin\cloud\config;
 
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
+
 /**
  * Common interfaces for cloud service provider (CloudConfig) plugins.
  *
@@ -63,4 +67,12 @@ interface CloudConfigPluginInterface {
    */
   public function getDefaultCreatedByUidTag(): string;
 
+  /**
+   * Check access privilege.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface;
+
 }
diff --git a/src/Plugin/cloud/config/CloudConfigPluginManager.php b/src/Plugin/cloud/config/CloudConfigPluginManager.php
index 230f08f8e749d76bafe910ada228aec0f280b1f8..df86575a0b2f8f51bc01fca1697c0b7363045b44 100644
--- a/src/Plugin/cloud/config/CloudConfigPluginManager.php
+++ b/src/Plugin/cloud/config/CloudConfigPluginManager.php
@@ -5,11 +5,14 @@ namespace Drupal\cloud\Plugin\cloud\config;
 use Drupal\cloud\Entity\CloudConfig;
 use Drupal\cloud\Plugin\cloud\CloudPluginManager;
 use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * Provides the default cloud_config_plugin manager.
@@ -265,4 +268,12 @@ class CloudConfigPluginManager extends CloudPluginManager implements CloudConfig
     return $this->plugin->getDefaultCreatedByUidTag();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    $this->setCloudContext($cloud_context);
+    return $this->plugin->access($cloud_context, $account, $route);
+  }
+
 }
diff --git a/src/Plugin/cloud/config/CloudConfigPluginManagerInterface.php b/src/Plugin/cloud/config/CloudConfigPluginManagerInterface.php
index 86d62206ddf642adb1594e4d5f33bdb98ce594e6..aad372deb9ada1a27a9890abca5aab3bafbc987b 100644
--- a/src/Plugin/cloud/config/CloudConfigPluginManagerInterface.php
+++ b/src/Plugin/cloud/config/CloudConfigPluginManagerInterface.php
@@ -3,6 +3,9 @@
 namespace Drupal\cloud\Plugin\cloud\config;
 
 use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * Defines an interface for cloud_config_plugin managers.
@@ -84,4 +87,12 @@ interface CloudConfigPluginManagerInterface extends PluginManagerInterface {
    */
   public function getDefaultCreatedByUidTag(): string;
 
+  /**
+   * Check access privilege.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface;
+
 }
diff --git a/src/Plugin/cloud/server_template/CloudServerTemplatePluginInterface.php b/src/Plugin/cloud/server_template/CloudServerTemplatePluginInterface.php
index 2960af17b5186ab5d7d9deab78ed33e54417fb93..95d835a711a61be1e9a204ecc5a1f4befbfe9127 100644
--- a/src/Plugin/cloud/server_template/CloudServerTemplatePluginInterface.php
+++ b/src/Plugin/cloud/server_template/CloudServerTemplatePluginInterface.php
@@ -3,7 +3,10 @@
 namespace Drupal\cloud\Plugin\cloud\server_template;
 
 use Drupal\cloud\Entity\CloudServerTemplateInterface;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * Common interfaces for a cloud launch template.
@@ -37,4 +40,12 @@ interface CloudServerTemplatePluginInterface {
    */
   public function launch(CloudServerTemplateInterface $cloud_server_template, FormStateInterface $form_state = NULL);
 
+  /**
+   * Check access privilege.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface;
+
 }
diff --git a/src/Plugin/cloud/server_template/CloudServerTemplatePluginManager.php b/src/Plugin/cloud/server_template/CloudServerTemplatePluginManager.php
index d510d4d9cadef5c7fdd03b7085f6b77533bb0606..7ea892dbfb3f4abe15fa4ea925db596742f9cf10 100644
--- a/src/Plugin/cloud/server_template/CloudServerTemplatePluginManager.php
+++ b/src/Plugin/cloud/server_template/CloudServerTemplatePluginManager.php
@@ -5,15 +5,18 @@ namespace Drupal\cloud\Plugin\cloud\server_template;
 use Drupal\cloud\Entity\CloudServerTemplateInterface;
 use Drupal\cloud\Plugin\cloud\CloudPluginManager;
 use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\Routing\Route;
 
 /**
  * Provides the default cloud_server_template_plugin manager.
@@ -288,4 +291,11 @@ class CloudServerTemplatePluginManager extends CloudPluginManager implements Clo
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface {
+    return $this->loadPluginVariant($cloud_context)->access($cloud_context, $account, $route);
+  }
+
 }
diff --git a/src/Plugin/cloud/server_template/CloudServerTemplatePluginManagerInterface.php b/src/Plugin/cloud/server_template/CloudServerTemplatePluginManagerInterface.php
index 420f9351b36d8e94d1d66d64ae9486b133feddf9..c243cdd5be10ec781a812e57e159b9d7e1914f32 100644
--- a/src/Plugin/cloud/server_template/CloudServerTemplatePluginManagerInterface.php
+++ b/src/Plugin/cloud/server_template/CloudServerTemplatePluginManagerInterface.php
@@ -4,7 +4,10 @@ namespace Drupal\cloud\Plugin\cloud\server_template;
 
 use Drupal\cloud\Entity\CloudServerTemplateInterface;
 use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Symfony\Component\Routing\Route;
 
 /**
  * Defines an interface for cloud_server_template_plugin managers.
@@ -82,4 +85,12 @@ interface CloudServerTemplatePluginManagerInterface extends PluginManagerInterfa
    */
   public function buildLaunchForm(CloudServerTemplateInterface $cloud_server_template, array &$form, FormStateInterface $form_state);
 
+  /**
+   * Check operation privilege by the API permissions of a cloud service.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   The access result.
+   */
+  public function access(string $cloud_context, AccountInterface $account, Route $route): AccessResultInterface;
+
 }
diff --git a/tests/src/Traits/CloudAssertionTrait.php b/tests/src/Traits/CloudAssertionTrait.php
index ab3dc01aa837c10a6f2fb94aad49f10fb64ba094..3df0f33eae8cccf316e201701edf18dde37b0b28 100644
--- a/tests/src/Traits/CloudAssertionTrait.php
+++ b/tests/src/Traits/CloudAssertionTrait.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\cloud\Traits;
 
+use Symfony\Component\HttpFoundation\Response;
+
 /**
  * The assertion trait for common usage.
  */
@@ -11,7 +13,7 @@ trait CloudAssertionTrait {
    * Assert successful/non-error responses.
    */
   protected function assertNoErrorMessage(): void {
-    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
     $this->assertSession()->pageTextNotContains($this->t('Error message'));
     $this->assertSession()->pageTextNotContains($this->t('Warning message'));
   }
@@ -20,7 +22,7 @@ trait CloudAssertionTrait {
    * Assert warning responses.
    */
   protected function assertWarningMessage(): void {
-    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
     $this->assertSession()->pageTextNotContains($this->t('Error message'));
     $this->assertSession()->pageTextContains($this->t('Warning message'));
   }
@@ -29,7 +31,7 @@ trait CloudAssertionTrait {
    * Assert error response.
    */
   protected function assertErrorMessage(): void {
-    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
     $this->assertSession()->pageTextNotContains($this->t('Warning message'));
     $this->assertSession()->pageTextContains($this->t('Error message'));
   }
@@ -38,7 +40,7 @@ trait CloudAssertionTrait {
    * Assert error response.
    */
   protected function assertWarningAndErrorMessage(): void {
-    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
     $this->assertSession()->pageTextContains($this->t('Warning message'));
     $this->assertSession()->pageTextContains($this->t('Error message'));
   }
@@ -52,4 +54,12 @@ trait CloudAssertionTrait {
     $this->assertEquals($errors[0]->getText(), $expected);
   }
 
+  /**
+   * Assert access denied.
+   */
+  protected function assertAccessDenied(): void {
+    $this->assertSession()->statusCodeEquals(Response::HTTP_FORBIDDEN);
+    $this->assertSession()->pageTextContains($this->t('Access Denied'));
+  }
+
 }
