全部产品
Search
文档中心

Elastic Compute Service:Audit dan perbaiki secara otomatis aturan grup keamanan yang tidak sesuai

更新时间:Nov 25, 2025

Jika suatu aturan grup keamanan membuka port yang rentan—seperti Port SSH 22 untuk Protokol Secure Shell (SSH) dan Port RDP 3389 untuk Protokol Desktop Jarak Jauh (RDP)—ke seluruh alamat IP (0.0.0.0/0), sistem Anda terpapar pada ancaman keamanan kritis. Anda dapat menggunakan Cloud Config untuk memantau konfigurasi grup keamanan secara berkelanjutan dan secara otomatis memperbaiki item konfigurasi yang tidak sesuai guna memastikan keamanan sistem.

Latar Belakang

Di lingkungan cloud perusahaan, grup keamanan merupakan metode inti untuk mengontrol lalu lintas jaringan dan menentukan aturan akses bagi instans server. Dalam skenario multi-instans yang kompleks, aturan grup keamanan mungkin mengandung konfigurasi berisiko akibat kelalaian operasi dan maintenance (O&M) atau desain kebijakan yang kurang tepat, seperti:

  • Port yang rentan diekspos ke seluruh rentang IP: Misalnya, membuka Port SSH 22, Port RDP 3389, atau port layanan database seperti 3306 dan 6379 ke Internet (0.0.0.0/0). Hal ini secara langsung mengekspos instans ke Internet, menjadikannya target utama serangan brute-force dan kebocoran data.

  • Pencampuran layanan internal dan publik: Gagal membedakan peran instans, seperti layanan web publik dan database internal. Hal ini dapat menyebabkan pemberian akses IP penuh secara keliru ke instans non-publik, menciptakan risiko pergerakan lateral di dalam jaringan internal.

Solusi

Anda dapat membuat aturan di Cloud Config untuk memantau perubahan pada aturan grup keamanan secara berkelanjutan. Aturan ini dikonfigurasi untuk mendeteksi apakah port yang rentan—seperti 22, 3389, dan 3306—dibuka ke publik. Jika aturan grup keamanan baru atau yang dimodifikasi mengizinkan akses ke port-port tersebut dari Internet, audit kepatuhan akan dipicu. Cloud Config kemudian secara otomatis memanggil Function Compute untuk menjalankan logika remediasi kustom. Logika ini menggunakan kit pengembangan perangkat lunak (SDK) Alibaba Cloud untuk menyesuaikan pengaturan grup keamanan, misalnya dengan menghapus aturan berisiko tersebut. Setelah remediasi, sistem mengevaluasi ulang aturan terkait untuk memastikan perbaikan telah berhasil. Anda juga dapat melihat detail remediasi untuk resource yang tidak sesuai di Konsol Cloud Config. Seluruh proses bersifat transparan dan dapat dilacak, sehingga secara efektif mencegah akses publik yang tidak sah. Solusi ini meningkatkan efisiensi O&M, mengurangi intervensi manual, dan memastikan konfigurasi resource selalu memenuhi persyaratan keamanan dan kepatuhan, sehingga meningkatkan keamanan dan stabilitas lingkungan Anda.

Buat aturan Cloud Config dan fungsi remediasi Function Compute

Solusi ini menggunakan Terraform untuk membuat aturan Cloud Config dan Function Compute guna secara otomatis memperbaiki resource yang tidak sesuai. Hal ini mengotomatiskan deteksi dan manajemen kepatuhan resource cloud.

Catatan

Jika Anda adalah Pengguna Resource Access Management (RAM), berikan izin berikut kepada Pengguna RAM tersebut. Untuk informasi selengkapnya, lihat Berikan izin kepada Pengguna RAM.

Kebijakan akses RAM

Kebijakan kustom ini memungkinkan pengguna untuk mengelola aturan grup keamanan Elastic Compute Service (ECS), serta layanan dan fungsi Function Compute.

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iacservice:CreateExplorerModuleVersion",
        "iacservice:GetExplorerModule",
        "iacservice:CreateExplorerModule",
        "iacservice:ListExplorerModules",
        "iacservice:UpdateExplorerModuleAttribute",
        "iacservice:DeleteExplorerModule"
      ],
      "Resource": "acs:iacservice:*:*:explorermodule/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iacservice:CreateExplorerTask",
        "iacservice:UpdateExplorerTaskAttribute",
        "iacservice:GetExplorerTask",
        "iacservice:DeleteExplorerTask"
      ],
      "Resource": "acs:iacservice:*:*:explorertask/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iacservice:CreateJob",
        "iacservice:GetJob",
        "iacservice:listJobs",
        "iacservice:OperateJob"
      ],
      "Resource": "acs:iacservice:*:*:explorertask/*/job/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iacservice:ListResources",
        "iacservice:ListExplorerHistories",
        "iacservice:CreateExplorerHistory",
        "iacservice:ExportTerraformCode"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecs:RevokeSecurityGroup",
        "ecs:DescribeSecurityGroups",
        "ecs:DescribeSecurityGroupAttributes"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "fc:CreateService",
        "fc:DeleteService",
        "fc:UpdateService",
        "fc:CreateFunction",
        "fc:DeleteFunction",
        "fc:UpdateFunction",
        "fc:InvokeFunction",
        "fc:ListServices",
        "fc:ListFunctions",
        "fc:GetService",
        "fc:GetFunction"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "config:*",
      "Resource": "*"
    }
  ]
}
Catatan

Kode contoh dalam tutorial ini dapat dijalankan dengan satu klik. Jalankan sekarang

Penting

Solusi ini menerapkan remediasi otomatis dengan langsung menghapus aturan grup keamanan yang tidak sesuai. Hal ini dapat memengaruhi kelangsungan bisnis. Anda dapat memodifikasi kode remediasi di Function Compute sesuai kebutuhan.

Kode Terraform

variable "region_id" {
  type    = string
  default = "cn-shenzhen"
}
# main.tf


provider "alicloud" {
  region     = var.region_id
}

resource "local_file" "python_script" {
  content  = <<EOF
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import sys

sys.path.append('/opt/python')
import json
import logging
import jmespath  # Gunakan jmespath sebagai pengganti jsonpath.
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_openapi.client import Client as OpenApiClient
from alibabacloud_openapi_util.client import Client as OpenApiUtilClient
from alibabacloud_tea_util import models as util_models

logger = logging.getLogger()


def handler(event, context):
    logger.info(f"Ini adalah event: {str(event, encoding='utf-8')}")
    get_resources_non_compliant(event, context)


def get_resources_non_compliant(event, context):
    # Dapatkan informasi tentang resource yang tidak sesuai.
    resources = parse_json(event)
    # Lakukan iterasi terhadap resource yang tidak sesuai dan lakukan remediasi.
    for resource in resources:
        remediation(resource, context)


def parse_json(content):
    """
    Uraikan string menjadi objek json
    :param content: konten string json
    :return: Objek Json
    """
    try:
        return json.loads(content)
    except Exception as e:
        logger.error('Gagal mengurai konten:{} menjadi json: {}.'.format(content, e))
        return None


def remediation(resource, context):
    logger.info(f"Informasi tentang resource yang akan diperbaiki: {resource}")
    region_id = resource['regionId']
    account_id = resource['accountId']
    resource_id = resource['resourceId']
    resource_type = resource['resourceType']
    if resource_type == 'ACS::ECS::SecurityGroup':
        # Dapatkan konfigurasi security group yang tidak sesuai dan verifikasi ulang untuk memastikan akurasi penilaian.
        resource_result = get_discovered_resource(context, resource_id, resource_type, region_id)
        configuration = json.loads(resource_result["body"]["DiscoveredResourceDetail"]["Configuration"])
        # Periksa apakah security group tersebut merupakan security group yang dikelola.
        is_managed_security_group = configuration.get('ServiceManaged')
        # Gunakan jmespath untuk mendapatkan ID aturan security group yang memiliki arah inbound dan memberikan akses ke 0.0.0.0/0.
        delete_security_group_rule_ids = jmespath.search(
            "Permissions.Permission[?SourceCidrIp=='0.0.0.0/0'].SecurityGroupRuleId",
            configuration
        )
        # Jika security group bukan security group yang dikelola dan memiliki aturan inbound yang memberikan akses ke 0.0.0.0/0, hapus aturan tersebut.
        if is_managed_security_group is False and delete_security_group_rule_ids:
            logger.info(f"Catatan: Menghapus aturan security group {region_id}:{resource_id}:{delete_security_group_rule_ids}")
            revoke_security_group(context, region_id, resource_id, delete_security_group_rule_ids)


def revoke_security_group(context, region_id, resource_id, security_group_rule_ids):
    creds = context.credentials
    config = open_api_models.Config(
        access_key_id=creds.access_key_id,
        access_key_secret=creds.access_key_secret,
        security_token=creds.security_token,
        endpoint=f'ecs.{region_id}.aliyuncs.com'
    )
    client = OpenApiClient(config)
    params = open_api_models.Params(
        style='RPC',  # Gaya API
        version='2014-05-26',  # Nomor versi API
        action='RevokeSecurityGroup',  # Nama API
        method='POST',  # Metode permintaan
        pathname='/',  # Jalur API. Jalur default untuk API RPC adalah "/".
        protocol='HTTPS',  # Protokol API.
        auth_type='AK',
        req_body_type='json',  # Format badan permintaan.
        body_type='json'  # Format badan respons.
    )
    query = {'RegionId': region_id, 'SecurityGroupId': resource_id, 'SecurityGroupRuleId': security_group_rule_ids}
    # Buat objek permintaan API.
    request = open_api_models.OpenApiRequest(
        query=OpenApiUtilClient.query(query),
    )
    runtime = util_models.RuntimeOptions()
    response = client.call_api(params, request, runtime)
    logger.info(f"Hasil penghapusan: {response}")


# Dapatkan detail resource.
def get_discovered_resource(context, resource_id, resource_type, region_id):
    """
    Panggil operasi API untuk mendapatkan detail konfigurasi resource.
    :param context: Konteks Function Compute.
    :param resource_id: ID resource.
    :param resource_type: Jenis resource.
    :param region_id: ID wilayah tempat resource berada.
    :return: Detail resource.
    """
    # Peran layanan untuk Function Compute (FC) harus memiliki izin AliyunConfigFullAccess.
    creds = context.credentials
    config = open_api_models.Config(
        access_key_id=creds.access_key_id,
        access_key_secret=creds.access_key_secret,
        security_token=creds.security_token,
        endpoint='config.cn-shanghai.aliyuncs.com'
    )
    client = OpenApiClient(config)
    params = open_api_models.Params(
        style='RPC',  # Gaya API
        version='2020-09-07',  # Nomor versi API
        action='GetDiscoveredResource',  # Nama API
        method='POST',  # Metode permintaan
        pathname='/',  # Jalur API. Jalur default untuk API RPC adalah "/".
        protocol='HTTPS',  # Protokol API.
        auth_type='AK',
        req_body_type='json',  # Format badan permintaan.
        body_type='json'  # Format badan respons.
    )
    query = {'ResourceId': resource_id, 'ResourceType': resource_type, 'Region': region_id}
    # Buat objek permintaan API.
    request = open_api_models.OpenApiRequest(
        query=OpenApiUtilClient.query(query),
    )
    runtime = util_models.RuntimeOptions()
    try:
        response = client.call_api(params, request, runtime)
        return response
    except Exception as e:
        logger.error('Kesalahan GetDiscoveredResource: %s' % e)

EOF
  filename = "${path.module}/python/index.py"
}

resource "local_file" "requirements_txt" {
  content  = <<EOF
  alibabacloud-tea-openapi
  jmespath>= 0.10.0
  EOF
  filename = "${path.module}/python/requests/requirements.txt"
}
locals {
  code_dir       = "${path.module}/python/"
  archive_output = "${path.module}/code.zip"
  base64_output  = "${path.module}/code_base64.txt"
}

data "archive_file" "code_package" {
  type        = "zip"
  source_dir  = local.code_dir
  output_path = local.archive_output

  depends_on = [
    local_file.python_script,
    local_file.requirements_txt,
  ]
}

resource "null_resource" "upload_code" {
  provisioner "local-exec" {
    command = <<EOT
    base64 -w 0 ${local.archive_output} > ${local.base64_output}
    EOT

    interpreter = ["sh", "-c"]
  }

  depends_on = [data.archive_file.code_package]
}

data "local_file" "base64_encoded_code" {
  filename   = local.base64_output
  depends_on = [null_resource.upload_code]
}
resource "alicloud_fcv3_function" "fc_function" {
  runtime       = "python3.10"
  handler       = "index.handler"
  function_name = "HHM-FC-TEST"
  role          = alicloud_ram_role.role.arn

  code {
    zip_file = data.local_file.base64_encoded_code.content
  }
  lifecycle {
    ignore_changes = [
      code
    ]
  }

  # Secara eksplisit atur log_config menjadi kosong.
  log_config {}

  depends_on = [data.local_file.base64_encoded_code]
}

resource "alicloud_config_rule" "default" {
  rule_name    = "SPM0014-sg-disallow-risky-ports-for-all-ips"
  description  = "Melarang security group membuka port rentan 22 dan 3389 ke seluruh rentang IP."
  source_owner = "ALIYUN"
  # (Wajib, ForceNew) Menentukan apakah aturan dimiliki dan dikelola oleh Anda atau Alibaba Cloud. Nilai yang valid: CUSTOM_FC: Aturan adalah aturan kustom milik Anda. ● ALIYUN: Aturan adalah aturan terkelola milik Alibaba Cloud.
  source_identifier = "sg-risky-ports-check"
  # Pengidentifikasi aturan. Untuk aturan terkelola, nilainya adalah nama aturan terkelola tersebut. Untuk aturan kustom, nilainya adalah Nama Sumber Daya Alibaba Cloud (ARN) dari aturan kustom tersebut. (Wajib, ForceNew)
  resource_types_scope = ["ACS::ECS::SecurityGroup"]
  # ID resource yang dikecualikan dari cakupan pemantauan. Pisahkan beberapa ID dengan koma (,). Parameter ini hanya berlaku untuk aturan yang dibuat berdasarkan aturan terkelola. Untuk aturan kustom, parameter ini kosong.
  config_rule_trigger_types = "ConfigurationItemChangeNotification" # Aturan dipicu saat konfigurasi berubah.
  # Nilai yang valid: One_Hour, Three_Hours, Six_Hours, Twelve_Hours, dan TwentyFour_Hours.
  risk_level = 1 #    ● 1: Kritis ● 2: Peringatan ● 3: Informasi

  input_parameters = {
    "ports" : "22,3389"
  }
}

resource "alicloud_config_remediation" "default" {
  config_rule_id          = alicloud_config_rule.default.id
  remediation_template_id = alicloud_fcv3_function.fc_function.function_arn
  remediation_source_type = "CUSTOM"
  invoke_type             = "AUTO_EXECUTION"
  params                  = "{}"
  remediation_type        = "FC"
}

resource "random_integer" "default" {
  min = 10000
  max = 99999
}

resource "alicloud_ram_role" "role" {
  name        = "tf-example-role-${random_integer.default.result}"
  document    = <<EOF
   {
    "Statement": [
       {
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
          "Service": [
            "fc.aliyuncs.com"
          ]
        }
      }
    ],
    "Version": "1"
  }
  EOF
  description = "Peran ram ECS."
  force       = true
}
resource "alicloud_ram_policy" "policy" {
  policy_name     = "tf-example-ram-policy-${random_integer.default.result}"
  policy_document = <<EOF
   {
    "Statement": [
       {
        "Action": [
          "config:GetDiscoveredResource",
          "ecs:RevokeSecurityGroup"
        ],
        "Effect":  "Allow",
        "Resource": ["*"]
      }
    ],
    "Version": "1"
  }
  EOF
  description     = "Ini adalah uji coba kebijakan."
  force           = true
}

resource "alicloud_ram_role_policy_attachment" "attach" {
  policy_name = alicloud_ram_policy.policy.policy_name
  policy_type = "Custom"
  role_name   = alicloud_ram_role.role.name
}

Lihat hasilnya

  1. Masuk ke konsol Cloud Config untuk melihat aturan yang telah dibuat.

    image

  1. Masuk ke konsol Function Compute untuk melihat fungsi yang telah dibuat.

image

Lihat hasil remediasi

Sebelum perbaikan

  1. Resource yang tidak sesuai ditampilkan di Cloud Config.

    image

  2. Login ke Konsol ECS untuk melihat grup keamanan.

    image

Setelah perbaikan

  1. Detail remediasi otomatis ditampilkan di Cloud Config.

    image

  1. Lihat grup keamanan di Konsol ECS setelah remediasi.

    image

Referensi