Skip to content

Commit 0bd06b8

Browse files
authored
feat!: migrate ufw to custom resources (#95)
* refactor: migrate ufw to custom resources Signed-off-by: Dan Webb <dan.webb@damacus.io> --------- Signed-off-by: Dan Webb <dan.webb@damacus.io>
1 parent 07b6be0 commit 0bd06b8

32 files changed

Lines changed: 613 additions & 567 deletions

.github/workflows/ci.yml

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,19 @@ jobs:
2222
strategy:
2323
matrix:
2424
os:
25-
# - almalinux-8
26-
# - almalinux-9
27-
# - amazonlinux-2023
28-
# - centos-7
29-
# - centos-stream-8
30-
# - centos-stream-9
31-
- debian-10
32-
- debian-11
3325
- debian-12
34-
# - fedora-latest
35-
# - opensuse-leap-15
36-
# - rockylinux-8
37-
# - rockylinux-9
38-
- ubuntu-1804
39-
- ubuntu-2004
26+
- debian-13
4027
- ubuntu-2204
28+
- ubuntu-2404
4129
suite:
4230
- default
4331
fail-fast: false
4432

4533
steps:
4634
- name: Check out code
4735
uses: actions/checkout@v5
48-
- name: Install Chef
49-
uses: actionshub/chef-install@main
36+
- name: Install Cinc Workstation
37+
uses: sous-chefs/.github/.github/actions/install-workstation@main
5038
- name: Dokken
5139
uses: actionshub/test-kitchen@main
5240
env:

.github/workflows/conventional-commits.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ name: conventional-commits
99
- edited
1010
- synchronize
1111

12+
permissions:
13+
pull-requests: read
14+
1215
jobs:
1316
conventional-commits:
1417
uses: sous-chefs/.github/.github/workflows/conventional-commits.yml@5.0.8

.github/workflows/prevent-file-change.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ name: prevent-file-change
99
- edited
1010
- synchronize
1111

12+
permissions:
13+
pull-requests: write
14+
1215
jobs:
1316
prevent-file-change:
1417
uses: sous-chefs/.github/.github/workflows/prevent-file-change.yml@5.0.8

.mise.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[env]
2+
_.path = "/opt/chef-workstation/bin"

.rubocop.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require:
2+
- cookstyle

Berksfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
# frozen_string_literal: true
2+
13
source 'https://supermarket.chef.io'
24

35
metadata
46

57
group :integration do
6-
cookbook 'apt'
8+
cookbook 'test', path: 'test/cookbooks/test'
79
end

Gemfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
source 'https://rubygems.org'
2+
3+
gem 'cookstyle'
4+
gem 'chefspec', '>= 9.3.7'
5+
gem 'berkshelf'
6+
gem 'fauxhai-chef'
7+
gem 'rspec-its'

LIMITATIONS.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Limitations
2+
3+
## Package Availability
4+
5+
### APT (Debian/Ubuntu)
6+
7+
- Debian 12 (Bookworm): `ufw` is available as the distro package `0.36.2-1`
8+
- Debian 13 (Trixie): `ufw` is available as the distro package `0.36.2-9`
9+
- Ubuntu 22.04 (Jammy): `ufw` is available as the distro package `0.36.1-4ubuntu0.1`
10+
- Ubuntu 24.04 (Noble): `ufw` is available as the distro package `0.36.2-6`
11+
12+
`ufw` is shipped by Debian and Ubuntu directly rather than through a separate upstream vendor
13+
APT repository, so this cookbook should rely on the platform package manager instead of adding a
14+
custom repository.
15+
16+
### DNF/YUM (RHEL family)
17+
18+
- No official `ufw` package path was identified for RHEL-family distributions that aligns with the
19+
current cookbook scope
20+
21+
### Zypper (SUSE)
22+
23+
- No official `ufw` package path was identified for SUSE distributions that aligns with the
24+
current cookbook scope
25+
26+
## Architecture Limitations
27+
28+
- Ubuntu publishes the `ufw` source package for architecture `all`, which indicates the package is
29+
architecture-independent
30+
- Debian publishes `ufw` from a single source package across the supported Debian suites in this
31+
cookbook, so the cookbook does not need architecture-specific package selection logic
32+
33+
## Source/Compiled Installation
34+
35+
### Build Dependencies
36+
37+
| Platform Family | Packages |
38+
| --------------- | ------------------------------ |
39+
| Debian | None for normal cookbook usage |
40+
41+
`ufw` is packaged as a distro-managed userspace tool and does not require a compiled-from-source
42+
installation flow for the supported Debian and Ubuntu targets in this cookbook.
43+
44+
## Known Issues
45+
46+
- This cookbook should stay Debian/Ubuntu-only unless a separate, verified package source is added
47+
for other platform families
48+
- Ubuntu 20.04 is no longer in standard support as of April 13, 2026, so it should not remain in
49+
the active test matrix
50+
- Debian 10 and Ubuntu 18.04 are fully out of support and should not remain in the active test
51+
matrix

README.md

Lines changed: 47 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,152 +1,79 @@
1-
# Description
1+
# ufw Cookbook
22

3-
Configures Uncomplicated Firewall (ufw) on Ubuntu and Debian. Including the `ufw` recipe in a run list means the firewall will be enabled and will deny everything except SSH and ICMP ping by default.
4-
5-
Rules may be added to the node by adding them to the `['firewall']['rules']` attributes in roles or on the node directly. The `firewall` cookbook has an LWRP that may be used to apply rules directly from other recipes as well. There is no need to explicitly remove rules, they are reevaluated on changes and reset. Rules are applied in the order of the run list, unless ordering is explicitly added.
3+
The `ufw` cookbook provides a single custom resource, `ufw_firewall`, for managing
4+
Uncomplicated Firewall on Debian and Ubuntu with the `firewall` cookbook's UFW provider.
65

76
## Requirements
87

98
### Platforms
109

11-
- Ubuntu
12-
- Debian
10+
- Debian 12+
11+
- Ubuntu 22.04+
1312

1413
### Chef
1514

16-
- Chef 15.3
15+
- Chef 15.3+
1716

1817
### Cookbooks
1918

20-
- firewall 2.0+
21-
22-
## Recipes
23-
24-
### default
25-
26-
The `default` recipe looks for the list of firewall rules to apply from the `['firewall']['rules']` attribute added to roles and on the node itself. The list of rules is then applied to the node in the order specified.
27-
28-
### disable
29-
30-
The `disable` recipe is used if there is a need to disable the existing firewall, perhaps for testing. It disables the ufw firewall even if other ufw recipes attempt to enable it.
31-
32-
If you remove this recipe, the firewall does not get automatically re-enabled. You will need clear the value of the `['firewall']['state']` to force a recalculation of the firewall rules. This can be done with `knife node edit`.
33-
34-
### databag
19+
- `firewall` 2.0+
3520

36-
The `databag` recipe looks in the `firewall` data bag for to apply firewall rules based on inspecting the runlist for roles and recipe names for keys that map to the data bag items and are applied in the the order specified.
21+
## Resource
3722

38-
The `databag` recipe calls the `default` recipe after the `['firewall']['rules']` attribute is set to apply the rules, so you may mix roles with databag items if you want (roles apply first, then data bag contents).
23+
### ufw_firewall
3924

40-
### recipes
41-
42-
The `recipes` recipe applies firewall rules based on inspecting the runlist for recipes that have node[\<recipe\>]['firewall']['rules'] attributes. These are appended to node['firewall']['rules'] and applied to the node. Cookbooks may define attributes for recipes like so:</recipe>
43-
44-
#### attributes/default.rb for test cookbook
25+
`ufw_firewall` installs and enables UFW, optionally opens SSH, and applies the provided rule set.
26+
It can also merge in rules discovered from a data bag or from legacy recipe-level firewall
27+
attributes during migration.
4528

4629
```ruby
47-
default['test']['firewall']['rules'] = [
48-
{"test"=> {
49-
"port"=> "27901",
50-
"protocol"=> "udp"
51-
}
52-
}
53-
]
54-
default['test::awesome']['firewall']['rules'] = [
55-
{"awesome"=> {
56-
"port"=> "99427",
57-
"protocol"=> "udp"
58-
}
59-
},
60-
{"awesome2"=> {
61-
"port"=> "99428"
62-
}
63-
}
64-
]
65-
```
66-
67-
Note that the 'test::awesome' rules are only applied if that specific recipe is in the runlist. Recipe-applied firewall rules are applied after any rules defined in role attributes.
68-
69-
### securitylevel
70-
71-
The `securitylevel` recipe is used if there are any node['firewall']['securitylevel'] settings that need to be enforced. It is a reference implementation with nothing configured.
72-
73-
## Attributes
74-
75-
Roles and the node may have the `['firewall']['rules']` attribute set. This attribute is a list of hashes, the key will be rule name, the value will be the hash of parameters. Application order is based on run list.
76-
77-
### Example Role
78-
79-
```ruby
80-
name "fw_example"
81-
description "Firewall rules for Examples"
82-
override_attributes(
83-
"firewall" => {
84-
"rules" => [
85-
{"tftp" => {}},
86-
{"http" => {
87-
"port" => "80"
88-
}
30+
ufw_firewall 'default' do
31+
allow_ssh true
32+
rules(
33+
[
34+
{ 'http' => { 'port' => '80' } },
35+
{ 'https' => { 'port' => '443' } },
36+
{
37+
'block-admin' => {
38+
'port' => '8443',
39+
'source' => '192.0.2.10',
40+
'action' => 'deny',
41+
},
8942
},
90-
{"block tomcat from 192.168.1.0/24" => {
91-
"port" => "8080",
92-
"source" => "192.168.1.0/24",
93-
"action" => "deny"
94-
}
95-
},
96-
{"Allow access to udp 1.2.3.4 port 5469 from 1.2.3.5 port 5469" => {
97-
"protocol" => "udp",
98-
"port" => "5469",
99-
"source" => "1.2.3.4",
100-
"destination" => "1.2.3.5",
101-
"dest_port" => "5469"
102-
}
103-
},
104-
{"allow to tcp ports 8000-8010 from 192.168.1.0/24" => {
105-
"port_range" => "8000..8010",
106-
"source" => "192.168.1.0/24",
107-
"protocol" => "tcp" //protocol is mandatory when using port ranges
108-
}
109-
}
11043
]
111-
}
11244
)
45+
action :create
46+
end
11347
```
11448

115-
- default['firewall']['allow_ssh'] Opens port 22 for SSH when set to true. Default set to true.
116-
117-
## Data Bags
49+
### Data bag-backed rules
11850

119-
The `firewall` data bag may be used with the `databag` recipe. It will contain items that map to role names (eg. the 'apache' role will map to the 'apache' item in the 'firewall' data bag). Either roles or recipes may be keys (role[webserver] is 'webserver', recipe[apache2] is 'apache2'). If you have recipe-specific firewall rules, you will need to replace the '::' with '**' (double underscores) (eg. recipe[apache2::mod_ssl] is 'apache2**mod_ssl' in the data bag item).
51+
```ruby
52+
ufw_firewall 'default' do
53+
data_bag_name 'firewall'
54+
action :create
55+
end
56+
```
12057

121-
The items in the data bag will contain a 'rules' array of hashes to apply to the `['firewall']['rules']` attribute.
58+
### Collect rules from other cookbooks' recipe attributes
12259

123-
```shell
124-
% knife data bag create firewall
125-
% knife data bag from file firewall examples/data_bags/firewall/apache2.json
126-
% knife data bag from file firewall examples/data_bags/firewall/apache2__mod_ssl.json
60+
```ruby
61+
ufw_firewall 'default' do
62+
collect_recipe_rules true
63+
action :create
64+
end
12765
```
12866

129-
### Example 'firewall' data bag item
130-
131-
```javascript
132-
{
133-
"id": "apache2",
134-
"rules": [
135-
{"http": {
136-
"port": "80"
137-
}},
138-
{"block http from 192.168.1.0/24": {
139-
"port": "80",
140-
"source": "192.168.1.0/24",
141-
"action": "deny"
142-
}}
143-
]
144-
}
145-
```
67+
### Remove UFW and reset the firewall
14668

147-
## Resources/Providers
69+
```ruby
70+
ufw_firewall 'default' do
71+
action :delete
72+
end
73+
```
14874

149-
The `firewall` cookbook provides the `firewall` and `firewall_rule` LWRPs, for which there is a ufw provider.
75+
See [`documentation/ufw_ufw_firewall.md`](documentation/ufw_ufw_firewall.md) for the full
76+
resource API.
15077

15178
## License & Authors
15279

attributes/default.rb

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)