Closed durkinza closed 11 months ago
Is there anybody working on this? I would love to see this in CDK soon.
I already have a draft ready, just waiting on a bar raiser to work with for the RFC.
If you have any comments or suggestions, I have the branch available here: https://github.com/durkinza/aws-cdk/tree/durkinza/network-firewall-l2
I have written a construct for the firewall already, as well, and published it as a construct to constructs.dev. It was'nt an option for me to wait. Can you publish it as a standalone contruct now?
Absolutely, I setup a quick construct library for now. constructs.dev: https://constructs.dev/packages/@durkinza/cdk-networkfirewall-l2/
TypeScript: https://www.npmjs.com/package/@durkinza/cdk-networkfirewall-l2 PyPi: https://pypi.org/project/durkinza.cdk-networkfirewall-l2/
I will work on getting some better documentation for the constructs. For now, this rfc can serve as a basic documentation, since the library uses the same structure. The library does have more options (specifically for logging); which are not in this RFC yet.
If you run into issues or would like to contribute, I have the source at https://github.com/durkinza/cdk-networkfirewall-l2
I would love to be able to read the suricata rules from a file instead of an inline string
The ability to import from files has been added for Suricata rule groups @hoegertn. Also I've updated the RFC with that call and the logging functions.
Closing this ticket. We believe the functionality is beneficial, but does not intersect with the core framework and should be vended and maintained separately.
Description
AWS Network Firewall is a stateful, managed, network firewall and intrusion detection and prevention service. These L2 Constructs can be used to create managed network firewalls with stateful and stateless rules and rule groups.
The goal of these constructs is to provide a way to decouple the creation of firewall rules from their rule groups and reduce the amount of boilerplate code required to define a network firewall.
The ideal examples shown below provide only the parameters required to create a resource. Wherever possible, optional parameters are available to give the same level of customization as the L1 API.
Defaults
To keep the constructs unopionionated, default actions are required for deployment of new resources. It may be possible to reduce boilerplate code more if default actions were to be defined. Some examples of possible opinionated approaches:
An unobtrusive logging approach, to promote implementation of network firewalls in existing stacks.
A more obtrusive, but higher security approach could be:
For new policies, it would also be possible to mirror the defaults set for security groups, where a default action of drop is set, with a single stateless rule being set to allow all outbound traffic. This approach would require generating an entire set of Policy, Stateless group, and stateless rule.
In any case a user can overwrite the default action(s) and create their own policies and rules as they see fit. Given the relatively small amount of code required to define the resources with default actions, I would opt to leave the code unopionionated for the first revision, as defaults can be specified in a later revision if needed.
Firewalls
An ideal implementation would allow users to create firewall with minimal boiler plate.
Where the firewall would be created in the provided vpc with the given firewall policy applied.
In this example,
policy
is defined only to meet the requirement that a firewall must have a firewall policy attached. As explained in the Defaults section above, it may be possible to generate a default policy when one is not provided.Firewall Policies
Firewall policy definitions can be done by referencing an existing name/ARN as shown in the last example, or by generating a new policy. Since a policy does not require rule groups to be attached, it will only need a few requirements to get started.
Editing an existing Policy (e.x. adding a rule group to an existing policy that has been referenced via ARN) would be out of scope.
When applying rule groups to a policy, a unique priority of must be provided for each group.
Stateless Rule Groups
Stateless firewall rule groups can be defined by referencing an existing name/ARN, or by generating a new group. New groups don't require any rules to be defined, so their implementation can be fairly quick.
The capacity requirements of a stateless rule group is fairly trivial to determine programmatically, but it can't be edited throughout the life time of the rule group. (ref) The stateless rule group could programmatically determine the capacity required for the rules assigned to it when no capacity is provided. Using the exact capacity requirements for a rule group by default may cause the user issues later if they decide to add another rule to the group.
Editing an existing rule-group (e.x. adding a rule to an existing group referenced via ARN) would be out of scope.
Stateless Rules
Stateless rules are not defined as a resource in AWS, they only exist in the context of the rule group they are defined in. To allow stateless rules to be decoupled from the rule group throughout the stack, they are defined as their own class, but reduce down to a L1
RuleDefinitionProperty
Assigning stateless rules to a stateless rule-group requires a priority mapping, similar to the way a rule-group requires a priority map when assigned to a policy.
Stateful Rule Groups
Stateful firewall rules are split into 3 categories (5Tuple, Suricata, Domain List). The console requires the category of rules to be defined when creating the rule group. However, from my understanding, the L1 constructs reduced all 3 down into Suricata rules. So a single stateful rule group could hold a mix of all 3 types of rules.
It appeared easier to merge the three types in a future revision than to split them apart if the requirements happened to change. I opted to match the AWS console, giving each rule group category has it's own class. Stateful rule groups are based on the same abstract class, to reduce duplicate code.
Stateful rule groups can be defined with no actionable rules within them, so the minimal implementation would be the same for all of them.
Stateful 5 Tuple Rules
To define a stateful 5tuple rule, all parameters must be provided to the L1 construct. In most cases the ANY keyword is used to generalize the rule as much as possible by default. Allowing the user to narrow down the rule as needed. A default action must be specified to determine what the rule does when it matches the traffic.
When adding the stateful 5Tuple rule to a stateful5Tuple rule-group, no priority is required, the ruleOrder assigned to the rule-group will be used.
Domain List Rules
When defining a Domain List, only a single set of targets can be provided, as set by the L1 construct. All Domain List specific parameters are required for this rule.
Suricata Rules
Suricata rules are just strings, so they don't have a class type, they are defined directly into the suricata rule-group.
Suricata rule groups can also be imported from a file.
All other arguments for creating a Suricata Rule Group are also supported here with an exception of the
rules
property.The
rules
property will be filled in with the contents from the file path, anything supplied will be ignored.Firewall Logs
Logging can be done using 3 AWS services, Cloud Watch trails, S3 buckets, and Kinesis Data Firehose streams.
The logging locations are configured with a Logging type, either Flow or Alert logs. In the case of Alert logs, it is up to the firewall policy to decide when a log should be generated.
Logs can be configured to be sent to multiple locations simultaneously.
Roles
Original feature request by @Obirah aws-cdk#19209
Workflow
status/proposed
)status/review
)api-approved
applied to pull request)status/final-comments-period
)status/approved
)status/planning
)status/implementing
)status/done
)