Фильтрация выходных данных интерфейса командной строки AWS для групп безопасности, имеющих определенные списки управления доступом для портов и IP-адресов.

У меня возникают трудности с фильтрацией выходных данных AWS CLI description-security-groups

Цель: найти все SG с правилами входа на порт 22 с cidr 0.0.0.0/0.

В собственных документах Amazon приводится пример, но указывается, что в их запросе есть ограничение, заключающееся в том, что он сначала отфильтрует весь набор данных для порта 22, а затем отфильтрует весь этот набор данных для 0.0.0.0/0. Это означает, что SG со следующими правилами по-прежнему будут срабатывать:

ingress 22 sg-12345678
ingress 443 0.0.0.0/0

Это полностью противоречит цели фильтрации, и я даже не уверен, почему Amazon предоставляет этот пример с заголовком «Для описания групп безопасности, которые имеют определенные правила».

Путь 1: сначала запрос aws cli, затем jq

Этот маршрут основан на том, что я нашел здесь: https://github.com/aws/aws-cli/issues/971

aws ec2 describe-security-groups --output json --query 'SecurityGroups[*].[GroupName,GroupId,IpPermissions[?ToPort==`22`].[IpRanges[?CidrIp==`0.0.0.0/0`]]]'

Который предоставляет список всех групп безопасности, но показывает вложенные данные для любых SG с 22 0.0.0.0/0 (и успешно игнорирует любые ACL 0.0.0.0/0 для других портов). Меня интересует SG1, а SG2/SG3 нужно отфильтровать.

[
    [
        "SG 1", 
        "sg-11111111", 
        [
            [
                [
                    {
                        "CidrIp": "0.0.0.0/0"
                    }
                ]
            ]
        ]
    ],
    [
        "SG 2",
        "sg-22222222",
        [
            [
                []
            ]
        ]
    ],
    [
        "SG 3", 
        "sg-33333333", 
        []
    ]
]

Это отличный первый шаг, так как я исключил списки ACL 0.0.0.0/0, которые не связаны с портом 22. Но когда я пытаюсь запустить jq, чтобы просто удалить записи с пустыми наборами данных, у меня возникают трудности, потому что все ключи разобраны.

  • Когда я пытаюсь выбрать более глубокие вложенные разделы, я получаю такие ошибки, как не могу выполнить итерацию по нулевому значению.
  • Если я попытаюсь использовать contains, я просто ничего не верну, поэтому я даже не уверен, где я ошибаюсь.

Путь 2: незапрошенные выходные данные CLI jq

Мне не удалось избежать ловушки исходного примера AWS, используя jq с самого начала, где я могу сначала запросить все SG, содержащие порт 22, а затем запросить любые ACL 0.0.0.0/0, какой из курс дает мне ложные срабатывания. Из-за потоковой природы jq я не понял, как проверить условие A (порт 22), а затем проверить условие B (0.0.0.0/0) только для элементов, связанных с условием A.

Вот некоторые очищенные необработанные выходные данные CLI для 2 SG, опять же, мне нужно получить первый, не вызывая ложного срабатывания на 2-м

{
    "SecurityGroups": [
        {
            "Description": "SG 1", 
            "IpPermissions": [
                {
                    "PrefixListIds": [], 
                    "FromPort": 22, 
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ], 
                    "ToPort": 22, 
                    "IpProtocol": "tcp", 
                    "UserIdGroupPairs": [], 
                    "Ipv6Ranges": []
                }
            ], 
            "GroupName": "SG 1",
            "VpcId": "vpc-12345678", 
            "OwnerId": "1234567890", 
            "GroupId": "sg-11111111"
        }, 
        {
            "Description": "SG 2", 
            "IpPermissions": [
                {
                    "PrefixListIds": [], 
                    "FromPort": 22, 
                    "IpRanges": [], 
                    "ToPort": 22, 
                    "IpProtocol": "tcp", 
                    "UserIdGroupPairs": [
                        {
                            "UserId": "1234567890", 
                            "GroupId": "sg-abcdefab"
                        }
                    ], 
                    "Ipv6Ranges": []
                },
                {
                    "PrefixListIds": [], 
                    "FromPort": 443, 
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ], 
                    "ToPort": 443, 
                    "IpProtocol": "tcp", 
                    "UserIdGroupPairs": [], 
                    "Ipv6Ranges": []
                }
            ], 
            "GroupName": "SG 2", 
            "VpcId": "vpc-12345678", 
            "OwnerId": "1234567890", 
            "GroupId": "sg-22222222"
        } 
    ]
}

person Ryan    schedule 25.10.2017    source источник
comment
еще одна проблема заключается в том, включен ли порт 22 в диапазон портов, т.е. если SG имеет диапазон портов 21-80, тогда ваш запрос не вернет этот SG.   -  person LHWizard    schedule 09.11.2017


Ответы (3)


Вам необходимо использовать расширенные условия JMESPath. Посмотрите, удовлетворяет ли приведенная ниже команда cli то, что вы просите.

aws ec2 describe-security-groups \
    --filters "Name=ip-permission.to-port,Values=22" \
    --query 'SecurityGroups[?IpPermissions[?ToPort==`22` && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]].{GroupId: GroupId, GroupName: GroupName}' \
    --output json \
    --region us-east-1
person Madhukar Mohanraju    schedule 25.10.2017
comment
Это похоже на то, что мне нужно. Любопытно, что раздел фильтров кажется избыточным, есть ли причина просто не удалять его, поскольку запрос — это то, что делает всю тяжелую работу. - person Ryan; 25.10.2017
comment
@Ryan: Ну, сначала я хотел сократить выходной набор только до групп безопасности, которые имеют to-port значение 22, а затем применить фильтры запросов, а не применять фильтры запросов ко всему набору с самого начала. - person Madhukar Mohanraju; 26.10.2017

Вот фильтр jq, который будет возвращать только SecurityGroups с IpPermission с FromPort = 22 и IpRange CidrIp «0.0.0.0/0»:

  .SecurityGroups[]
| select(.IpPermissions[] | .FromPort == 22 and .IpRanges[].CidrIp == "0.0.0.0/0")

Пример запуска (при условии, что фильтр в filter.jq и данные в data.json)

$ jq -M -f filter.jq data.json
{
  "Description": "SG 1",
  "IpPermissions": [
    {
      "PrefixListIds": [],
      "FromPort": 22,
      "IpRanges": [
        {
          "CidrIp": "0.0.0.0/0"
        }
      ],
      "ToPort": 22,
      "IpProtocol": "tcp",
      "UserIdGroupPairs": [],
      "Ipv6Ranges": []
    }
  ],
  "GroupName": "SG 1",
  "VpcId": "vpc-12345678",
  "OwnerId": "1234567890",
  "GroupId": "sg-11111111"
}

Попробуйте онлайн на jqplay.org

person jq170727    schedule 25.10.2017
comment
Я пробовал что-то в этом роде, но, очевидно, мне это не удалось, поскольку все, что я когда-либо получал, было синтаксическими ошибками. Большое спасибо за это, хотя я не использую это решение в этот раз, оно, вероятно, пригодится в какой-то момент в будущем. - person Ryan; 26.10.2017

Решение jq для фильтрации групп безопасности с пустыми вложенными данными:

aws ec2 describe-security-groups --output json --query 'SecurityGroups[*].[GroupName,GroupId,IpPermissions[?ToPort==`22`]
.[IpRanges[?CidrIp==`0.0.0.0/0`]]]' | jq 'map(select(.[2] | flatten | length > 0))'

Выход:

[
  [
    "SG 1",
    "sg-11111111",
    [
      [
        [
          {
            "CidrIp": "0.0.0.0/0"
          }
        ]
      ]
    ]
  ]
]
person RomanPerekhrest    schedule 25.10.2017
comment
Это решение намного короче, чем я ожидал для маршрута 1. Хотя я не использую его, я могу вернуться к этому ответу, чтобы выяснить, что именно здесь делается. - person Ryan; 26.10.2017