Back to Checks
aws

EC2 instance is managed by AWS Systems Manager or not running

ec2_instance_managed_by_ssm
Service: ec2Severity: medium
OfficialBuilt-inVerified
Categories:node-security
Resource Type:AwsEc2Instance

EC2 instances are assessed for enrollment as Systems Manager managed nodes. Running instances lacking Systems Manager registration are marked as unmanaged; instances in stopped, terminated, or pending states are noted separately.

Risk

Unmanaged instances lack centralized patching, inventory, and secure remote access. This increases exposure to brute force on SSH/RDP, delayed patching, and poor visibility. Exploits can enable lateral movement and persistence, degrading confidentiality, integrity, and availability.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks ec2_instance_managed_by_ssm

Recommendation

Enroll all instances as Systems Manager managed nodes. Prefer Session Manager over SSH/RDP, restrict inbound admin ports, and use least privilege roles. Ensure connectivity to SSM endpoints (or private endpoints), automate patching and inventory, and monitor activity for defense-in-depth.

Remediation

CLI

aws ec2 stop-instances --instance-ids <INSTANCE_ID>

Terraform

# Terraform: make the instance SSM-managed by attaching the required IAM role
resource "aws_iam_role" "<example_resource_name>" {
  name               = "<example_resource_name>"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = { Service = "ec2.amazonaws.com" }
      Action   = "sts:AssumeRole"
    }]
  })
}

resource "aws_iam_role_policy_attachment" "<example_resource_name>_ssm" {
  role       = aws_iam_role.<example_resource_name>.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"  # CRITICAL: grants SSM permissions required for management
}

resource "aws_iam_instance_profile" "<example_resource_name>" {
  name = "<example_resource_name>"
  role = aws_iam_role.<example_resource_name>.name
}

resource "aws_instance" "<example_resource_name>" {
  ami                  = "ami-<example_resource_id>"
  instance_type        = "t3.micro"
  iam_instance_profile = aws_iam_instance_profile.<example_resource_name>.name  # CRITICAL: attaches the SSM-enabled role to the instance
}

NativeIaC

# CloudFormation: make the instance SSM-managed by attaching the required IAM role
Resources:
  <example_resource_name>Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore  # CRITICAL: grants SSM permissions required for management

  <example_resource_name>InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref <example_resource_name>Role

  <example_resource_name>Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-<example_resource_id>
      InstanceType: t3.micro
      IamInstanceProfile: !Ref <example_resource_name>InstanceProfile  # CRITICAL: attaches the SSM-enabled role to the instance

Other

1In IAM console: Create role > AWS service > EC2 > Next; attach policy "AmazonSSMManagedInstanceCore"; Create role
2In EC2 console: Instances > select the instance > Actions > Security > Modify IAM role > choose the role created above > Update IAM role
3Wait a few minutes; in Systems Manager console: Managed nodes, verify the instance shows as Online
4If the instance OS does not include SSM Agent by default, install the SSM Agent for that OS, then verify again

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ssm.ssm_client import ssm_client


class ec2_instance_managed_by_ssm(Check):
    def execute(self):
        findings = []
        for instance in ec2_client.instances:
            report = Check_Report_AWS(metadata=self.metadata(), resource=instance)
            report.resource_arn = instance.arn
            report.resource_tags = instance.tags
            report.status = "PASS"
            report.status_extended = (
                f"EC2 Instance {instance.id} is managed by Systems Manager."
            )
            report.resource_id = instance.id
            # instances not running should pass the check
            if instance.state in ["pending", "terminated", "stopped"]:
                report.status_extended = f"EC2 Instance {instance.id} is unmanaged by Systems Manager because it is {instance.state}."
            elif not ssm_client.managed_instances.get(instance.id):
                report.status = "FAIL"
                report.status_extended = (
                    f"EC2 Instance {instance.id} is not managed by Systems Manager."
                )
            findings.append(report)

        return findings