Class: Mt::Wall::DSL::RootBuilder
- Inherits:
-
Object
- Object
- Mt::Wall::DSL::RootBuilder
- Includes:
- PolicyScope, RuleScope
- Defined in:
- lib/mt/wall/dsl/root_builder.rb
Overview
Top-level DSL context. The public methods here are the verbs users write in firewall config files / blocks. Each verb validates its arguments and records a Model::* value object on the Configuration.
‘rule` (Layer-A access grants) comes from RuleScope; `policy` (chain defaults) comes from PolicyScope, shared with DeviceBuilder so the same syntax sets a global default here and overrides it inside a `device` block. The `device` block itself configures Layer-B box firewall and does NOT take `rule`.
Target DSL (not yet implemented):
host "web" do
address "10.0.0.5"
address "10.0.1.0/24"
member_of "web-prod", "web-wordpress"
end
host "db", address: "10.0.2.10" # one-line shorthand
host "web", "web-prod", "web-wordpress",
address: ["10.0.0.5", "10.0.1.0/24"] # + groups
group "frontend" do
member "web"
end
service "mysql", protocol: :tcp, ports: [3306]
rule "frontend" do # grants grouped by source
to "db", "mysql" # allow (default)
to "db", "mysql", :deny
end
policy :forward, :drop # global default
device "edge-1", host: "10.0.0.1", transport: :rest_api do
policy :input, :drop # override for this box
input do # the box's own firewall
allow_established
drop_invalid
accept protocol: :tcp, dst_port: 22, src: "admin"
end
end
Instance Method Summary collapse
- #device(name, host:, transport: :rest_api, **options) { ... } ⇒ void
- #group(name, comment: nil) { ... } ⇒ void
-
#host(name, *groups, address: nil, comment: nil) { ... } ⇒ void
A named address object (host).
-
#initialize(configuration) ⇒ RootBuilder
constructor
A new instance of RootBuilder.
- #record_policy(policy) ⇒ void
-
#record_rule(rule) ⇒ void
RuleScope storage hooks (record onto the Configuration).
-
#service(name, protocol: nil, protocols: nil, ports: []) ⇒ void
A named protocol/port definition.
Methods included from PolicyScope
Methods included from RuleScope
Constructor Details
#initialize(configuration) ⇒ RootBuilder
Returns a new instance of RootBuilder.
52 53 54 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 52 def initialize(configuration) @configuration = configuration end |
Instance Method Details
#device(name, host:, transport: :rest_api, **options) { ... } ⇒ void
This method returns an undefined value.
122 123 124 125 126 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 122 def device(name, host:, transport: :rest_api, **, &block) builder = DeviceBuilder.new(name, host: host, transport: transport, **) builder.instance_eval(&block) if block @configuration.add_device(builder.to_device) end |
#group(name, comment: nil) { ... } ⇒ void
This method returns an undefined value.
97 98 99 100 101 102 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 97 def group(name, comment: nil, &block) builder = GroupBuilder.new(name, comment: comment) builder.instance_eval(&block) if block group = builder.to_group @configuration.declare_group(group.name, group.members, group.comment) end |
#host(name, *groups, address: nil, comment: nil) { ... } ⇒ void
This method returns an undefined value.
A named address object (host). Trailing positional args after the name are group names this host joins (same as ‘member_of` in the block form); addresses come from the `address:` shorthand (a single string or an array, normalized via Array()) or an `address` block.
AUTO-CREATE is NARROW: a group referenced HERE (host-side membership) is created on demand, because the host contributes real addresses to it. Groups referenced from ‘rule` / `src:` / `dst:` are NOT auto-created — an empty/undeclared group there is a fail-fast error in the Compiler.
FAIL-FAST validation:
* a positional `groups` token that parses as an IP/CIDR via IPAddr
raises ConfigurationError ("looks like an address — did you mean
address:?") — guards the common `host "web", "10.0.0.5"` slip;
* a host that ends up with NO addresses raises ConfigurationError;
* `name` and every group token must match `\A[\w.-]+\z`.
host "web", "web-prod", address: "10.0.0.5"
host "web", "web-prod", address: ["10.0.0.5", "10.0.1.0/24"]
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 80 def host(name, *groups, address: nil, comment: nil, &block) memberships = groups.map { |token| Validators.validate_group_token!(token) } builder = HostBuilder.new(name, comment: comment) builder.instance_eval(&block) if block Array(address).each { |entry| builder.address(entry) } object = builder.to_object @configuration.add_object(object) (memberships + builder.memberships).uniq.each do |group_name| @configuration.add_membership(object.name, group_name) end end |
#record_policy(policy) ⇒ void
This method returns an undefined value.
135 136 137 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 135 def record_policy(policy) @configuration.add_global_policy(policy) end |
#record_rule(rule) ⇒ void
This method returns an undefined value.
RuleScope storage hooks (record onto the Configuration).
130 131 132 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 130 def record_rule(rule) @configuration.add_rule(rule) end |
#service(name, protocol: nil, protocols: nil, ports: []) ⇒ void
This method returns an undefined value.
A named protocol/port definition. Accepts a single ‘protocol:` (legacy) OR multiple `protocols:` (e.g. DNS = tcp+udp). Ports keep their spec form (Integer/Array/Range/“a-b”), so a range round-trips as a range.
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/mt/wall/dsl/root_builder.rb', line 108 def service(name, protocol: nil, protocols: nil, ports: []) list = protocols || protocol raise ConfigurationError, "service #{name.inspect} needs protocol: or protocols:" if list.nil? validated = Array(list).map { |proto| Validators.validate_protocol!(proto) } @configuration.add_service( Model::Service.new(name: Validators.validate_name!(name, label: "service"), protocols: validated, ports: Validators.validate_ports!(ports)) ) end |