Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build/
out/
[\.]*~
6 changes: 6 additions & 0 deletions base/comps/azurelinux-config/50-default.network
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# We want systemd to manage all interfaces
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ddstreetmicrosoft I believe you had some input on the right approach here, what other distros typically do, etc.?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most robust approach is to let one framework manage all interfaces. Given we are considering only azure cloud deployments I would rather not complicate things. I see there may be cases where the machine is in a DMZ zone and can have NICs in different networks. Let us consider those as special cases to be handled by the customer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I should have clarified. My question was more around blanket DHCP enablement -- not having systemd-networkd manage the network interfaces.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Match]
Name=*

[Network]
DHCP=yes
2 changes: 2 additions & 0 deletions base/comps/azurelinux-config/azurelinux-config.comp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[components.azurelinux-config]
spec = { type = "local", path = "azurelinux-config.spec" }
60 changes: 60 additions & 0 deletions base/comps/azurelinux-config/azurelinux-config.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
%define is_development 1

Summary: Azure Linux configuration override meta-package
Name: azurelinux-config
Version: 4.0
Release: %autorelease %[0%{?is_development} ? "-p" : ""]
License: MIT
URL: https://aka.ms/azurelinux

Source1: 50-default.network
Source2: azurelinux-firewalld-zone.xml
Source3: firewalld-azurelinux.conf

BuildArch: noarch

%description
Provides AZL specific configuration overrides via sub-packages. These sub-packages will be pulled in by the relevant owning packages via reverse dependencies.


%package systemd-networkd
Summary: Azure Linux specific configuration for systemd-networkd.
Requires: systemd-networkd
# This is a reverse dependency to make systemd-networkd pull-in this package.
# It is still experimental. Consider this as a placeholder.
Supplements: systemd-networkd

%description systemd-networkd
Provides systemd-networkd configuration installed at /etc/systemd/network which asks systemd to manage all interfaces on the system.

%package firewalld
Summary: Azure Linux firewall policies
Requires: firewalld
Supplements: firewalld

%description firewalld
Provides Azure Linux specific policies and zones for firewalld.

%install
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as with the other PR, distro-provided files should go into /usr/lib; the /etc dir is generally for users/admins

install -d %{buildroot}%{_sysconfdir}/systemd/network
install -m 644 %{SOURCE1} %{buildroot}%{_sysconfdir}/systemd/network/50-default.network
install -d %{buildroot}%{_sysconfdir}/firewalld/zones
install -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/firewalld/zones/azurelinux.xml
install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/firewalld/firewalld-azurelinux.conf

# We need the post/postun symlink to avoid littering /etc/firewalld with rpm save files.
%post firewalld
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being installed via %post? Can the symlinks be included directly in %files?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assumed since there will be an existing symlink to the default conf, install may fail. I will verify and if it works do it via %files.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't realize another package owns this .conf file.

Interestingly the Fedora guide uses firewalld.conf as a specific example here: https://docs.fedoraproject.org/en-US/packaging-guidelines/Per-Product_Configuration/ -- with some guidance on per-product configs. That sounds applicable?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, now that I'm reading through the upstream firewalld.spec -- this seems like a case where they expect the base firewalld package to carry product-specific .conf files and to switch on VARIANT_ID to select the right one.

There's an interesting question here as to what our VARIANT_ID will be and whether we should go with an overlay as opposed to the layered config package that re-symlinks.

If both firewalld and our config package are both trying to symlink -- is there a risk that they'll thrash? i.e., if firewalld happens to get reinstalled/upgraded, will it "steal the symlink back"?

ln -sf %{_sysconfdir}/firewalld/firewalld-azurelinux.conf %{_sysconfdir}/firewalld/firewalld.conf

%postun firewalld
ln -sf %{_sysconfdir}/firewalld/firewalld-standard.conf %{_sysconfdir}/firewalld/firewalld.conf
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The %postun script references 'firewalld-standard.conf' which may not exist. When the package is uninstalled, this symlink creation will fail if the target file doesn't exist. Consider verifying the file exists or using a conditional check before creating the symlink.

Suggested change
ln -sf %{_sysconfdir}/firewalld/firewalld-standard.conf %{_sysconfdir}/firewalld/firewalld.conf
if [ -f %{_sysconfdir}/firewalld/firewalld-standard.conf ]; then
ln -sf %{_sysconfdir}/firewalld/firewalld-standard.conf %{_sysconfdir}/firewalld/firewalld.conf
fi

Copilot uses AI. Check for mistakes.

%files systemd-networkd
%config(noreplace) /etc/systemd/network/50-default.network

%files firewalld
%config(noreplace) /etc/firewalld/zones/azurelinux.xml
%config(noreplace) /etc/firewalld/firewalld-azurelinux.conf

%changelog
%autochangelog
10 changes: 10 additions & 0 deletions base/comps/azurelinux-config/azurelinux-firewalld-zone.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<zone>
Comment thread
reubeno marked this conversation as resolved.
Comment thread
reubeno marked this conversation as resolved.
<short>azurelinux</short>
<description>For use in azure cloud vms with zero trust policy. Only ssh is allowed by default. If we need dynamic IPv6 addressing dhcpv6-client will have to be enabled.</description>
<service name="ssh"/>
<!--
<service name="dhcpv6-client"/>
-->
<forward/>
Comment thread
reubeno marked this conversation as resolved.
</zone>
121 changes: 121 additions & 0 deletions base/comps/azurelinux-config/firewalld-azurelinux.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# firewalld config file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would greatly like to see a PR with individual commits for every single configuration parameter added here, with specific explanation for why we need to add the config


# default zone
# The default zone used if an empty zone string is used.
# Default: public
DefaultZone=azurelinux

# Clean up on exit
# If set to no or false the firewall configuration will not get cleaned up
# on exit or stop of firewalld.
# Default: yes
CleanupOnExit=yes
Comment thread
reubeno marked this conversation as resolved.

# Clean up kernel modules on exit
# If set to yes or true the firewall related kernel modules will be
# unloaded on exit or stop of firewalld. This might attempt to unload
# modules not originally loaded by firewalld.
# Default: no
CleanupModulesOnExit=no

# IPv6_rpfilter
# Performs reverse path filtering (RPF) on IPv6 packets as per RFC 3704.
# Possible values:
# - strict: Performs "strict" filtering as per RFC 3704. This check
# verifies that the in ingress interface is the same interface
# that would be used to send a packet reply to the source. That
# is, ingress == egress.
# - loose: Performs "loose" filtering as per RFC 3704. This check only
# verifies that there is a route back to the source through any
# interface; even if it's not the same one on which the packet
# arrived.
# - strict-forward: This is almost identical to "strict", but does not perform
# RPF for packets targeted to the host (INPUT).
# - loose-forward: This is almost identical to "loose", but does not perform
# RPF for packets targeted to the host (INPUT).
# - no: RPF is completely disabled.
#
# The rp_filter for IPv4 is controlled using sysctl.
# Note: This feature has a performance impact. See man page FIREWALLD.CONF(5)
# for details.
# Default: strict
IPv6_rpfilter=strict

# IndividualCalls
# Do not use combined -restore calls, but individual calls. This increases the
# time that is needed to apply changes and to start the daemon, but is good for
# debugging.
# Default: no
IndividualCalls=no

# LogDenied
# Add logging rules right before reject and drop rules in the INPUT, FORWARD
# and OUTPUT chains for the default rules and also final reject and drop rules
# in zones. Possible values are: all, unicast, broadcast, multicast and off.
# Default: off
LogDenied=off

# FirewallBackend
# Selects the firewall backend implementation.
# Choices are:
# - nftables (default)
# - iptables (iptables, ip6tables, ebtables and ipset)
# Note: The iptables backend is deprecated. It will be removed in a future
# release.
FirewallBackend=nftables

# FlushAllOnReload
# Flush all runtime rules on a reload. In previous releases some runtime
# configuration was retained during a reload, namely; interface to zone
# assignment, and direct rules. This was confusing to users. To get the old
# behavior set this to "no".
# Default: yes
FlushAllOnReload=yes

# ReloadPolicy
# Policy during reload. By default all traffic except for established
# connections is dropped while the rules are updated. Set to "DROP", "REJECT"
# or "ACCEPT". Alternatively, specify it per table, like
# "OUTPUT:ACCEPT,INPUT:DROP,FORWARD:REJECT".
# Default: ReloadPolicy=INPUT:DROP,FORWARD:DROP,OUTPUT:DROP
ReloadPolicy=INPUT:DROP,FORWARD:DROP,OUTPUT:DROP

# RFC3964_IPv4
# As per RFC 3964, filter IPv6 traffic with 6to4 destination addresses that
# correspond to IPv4 addresses that should not be routed over the public
# internet.
# Defaults to "yes".
RFC3964_IPv4=yes

# StrictForwardPorts
# If set to yes, the generated destination NAT (DNAT) rules will NOT accept
# traffic that was DNAT'd by other entities, e.g. docker. Firewalld will be
# strict and not allow published container ports until they're explicitly
# allowed via firewalld.
# If set to no, then docker (and podman) integrates seamlessly with firewalld.
# Published container ports are implicitly allowed.
# Defaults to "no".
StrictForwardPorts=no

# NftablesFlowtable
# This may improve forwarded traffic throughput by enabling nftables flowtable.
# It is a software fastpath and avoids calling nftables rule evaluation for
# data packets. This only works for TCP and UDP traffic.
# The value is a space separated list of interfaces.
# Example value "eth0 eth1".
# Defaults to "off".
NftablesFlowtable=off

# NftablesCounters
# If set to yes, add a counter to every nftables rule. This is useful for
# debugging and comes with a small performance cost.
# Defaults to "no".
NftablesCounters=no

# NftablesTableOwner
# If set to yes, the generated nftables rule set will be owned exclusively by
# firewalld. This prevents other entities from mistakenly (or maliciously)
# modifying firewalld's rule set. If you intentionally modify firewalld's
# rules, then you will have to set this to "no".
# Defaults to "yes".
NftablesTableOwner=yes
1 change: 1 addition & 0 deletions base/comps/components.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ spec = { type = "upstream", upstream-distro = { name = "fedora", version = "rawh
[components.file]
[components.filesystem]
[components.findutils]
[components.firewalld]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this PR both adding the firewalld package itself, and adding azl-specific config in a separate package? IMHO simply adding firewalld should be completely separate - that should be simple to review/commit.

[components.fonts-rpm-macros]
[components.fstrm]
[components.fuse]
Expand Down
6 changes: 3 additions & 3 deletions base/images/images.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# [images.vm-base]
# description = "VM Base Image"
# definition = { type = "kiwi", path = "vm-base/vm-base.kiwi" }
[images.vm-base]
description = "VM Base Image"
definition = { type = "kiwi", path = "vm-base/vm-base.kiwi" }

# [images.container-base]
# description = "Container Base Image"
Expand Down
14 changes: 7 additions & 7 deletions base/images/vm-base/vm-base.kiwi
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
format="vhdx"
initrd_system="dracut"
filesystem="ext4"
kernelcmdline="console=ttyS0 rd.shell=0 systemd.getty_auto=false"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do these changes have to do with firewalld configuration overrides?

kernelcmdline="console=ttyS0 rd.shell=0"
firmware="uefi"
overlayroot="false"
eficsm="false"
bootpartition="false"
efipartsize="200">
<bootloader name="systemd_boot" timeout="0" />
<size unit="G">2</size>
<size unit="G">4</size>
<initrd action="setup">
<dracut uefi="true"/>
</initrd>
Expand Down Expand Up @@ -56,6 +56,8 @@
<package name="dnf" />
<package name="dracut-config-generic" />
<package name="dracut-kiwi-oem-repart"/>
<package name="firewalld"/>
<package name="azurelinux-config-firewalld"/>
<package name="glibc-langpack-en" />
<package name="glibc-locale-source" />
<package name="glibc-minimal-langpack" />
Expand Down Expand Up @@ -86,7 +88,7 @@
<package name="sudo" />
<package name="systemd-boot" />
<package name="systemd-networkd" />
<package name="systemd-resolved" />
<package name="azurelinux-config-systemd-networkd" />
Comment thread
reubeno marked this conversation as resolved.
<package name="systemd-resolved" />
<package name="systemd" />
<package name="tar" />
Expand Down Expand Up @@ -114,9 +116,7 @@
<package name="system-release" />
</packages>

<!--
<users>
<user name="root" password="INSERT-PASSWORD-HERE" groups="root" />
<user name="root" password="INSERT-PASSWORD-HERE" groups="root" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these changes; you should be able to use cloud-init config to inject user account configs / credentials (e.g., via azldev image boot).

I'm happy to chat separately to get you unblocked with that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops!

</users>
-->
</image>
</image>
2 changes: 1 addition & 1 deletion distro/azurelinux.distro.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ spec = { type = "upstream", upstream-distro = { name = "fedora", version = "43"
dist = ".azl4"
vendor = "Microsoft Corporation"
distribution = "Azure Linux"
rhel = "10"
rhel = "11"
81 changes: 66 additions & 15 deletions scripts/demo-build.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#!/bin/bash
set -euxo pipefail
set -euo pipefail
exec 3> ./demo-build.trc
BASH_XTRACEFD=3
set -x

echo -e "\e[0;33mbash trace, -x output is in ./demo-build.trc\e[0m"

#
# NOTE: This script is a throwaway script. Please think ~~twice~~ thrice before you
# consider adding anything to it.
# consider adding anything to it. Let us push all dev-tooling into azldev.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed!

#

# Confirm working dir.
Expand All @@ -13,29 +18,75 @@ if [ ! -f azldev.toml ]; then
fi

# Check prereqs.
for prereq in azldev kiwi createrepo_c docker; do
for prereq in azldev kiwi createrepo_c docker mock qemu-system-x86_64 ; do
if ! command -v $prereq >/dev/null 2>&1; then
echo "ERROR: Missing prerequisite '$prereq'." >&2
exit 1
fi
done

# Build azurelinux-rpm-config to generate system macros, etc.
if [ "$(getenforce)" != "Permissive" ] ; then
echo "SElinux is not set to 'Permissive'."
echo "That is required for kiwi to build images, aborting."
exit 1
fi

if [[ "$#" -ne 1 || ! "$1" =~ container|vm|vm-boot ]] ; then
echo "Usage: $0 <container|vm|vm-boot>"
echo "Build container or vm image, or build vm image and boot with qemu."
exit 1
fi

image_type="$1"
echo "Building a \"$image_type\" image"

# Build azurelinux-rpm-config to generate systemd macros, etc.
azldev comp build azurelinux-rpm-config && createrepo_c ./base/out

# Build azurelinux-release and azurelinux-repos to provide repo files and release info.
# They require the rpm-config package to be built first.
azldev comp build azurelinux-release --local-repo ./base/out && createrepo_c ./base/out
azldev comp build azurelinux-repos --local-repo ./base/out && createrepo_c ./base/out
azldev comp build azurelinux-config --local-repo ./base/out && createrepo_c ./base/out

# Build rpm to ensure the azl-specific vendor tag is configured.
azldev comp build rpm --local-repo ./base/out && createrepo_c ./base/out
# Build a base container image using these private RPMs and upstream Fedora packages.
sudo kiwi --loglevel 10 \
--kiwi-file container-base.kiwi \
system build \
--description ./base/images/container-base \
--target-dir ./base/out/images \
--add-repo="file:///$PWD/base/out,rpm-md,azl,1"

# Run a command in the container to verify.
xzcat ./base/out/images/azl4-container-base.x86_64-0.1.docker.tar.xz | docker load
docker run -it --rm microsoft/azurelinux/base/core:4.0 cat /etc/os-release

function build_container_image() {
# Build a base container image using these private RPMs and upstream Fedora packages.
sudo kiwi --loglevel 10 \
--kiwi-file container-base.kiwi \
system build \
--description ./base/images/container-base \
--target-dir ./base/out/images \
--add-repo="file:///$PWD/base/out,rpm-md,azl,1"

# Run a command in the container to verify.
xzcat ./base/out/images/azl4-container-base.x86_64-0.1.docker.tar.xz | docker load
docker run -it --rm microsoft/azurelinux/base/core:4.0 cat /etc/os-release
}

function build_vm_image() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you have a moment, try using azldev image build and azldev image boot. Holler if you have difficulty.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is the invocation here. Did you mean to say get rid of the function wrapper?

# Build the VM image using kiwi via azldev
azldev image build vm-base --local-repo base/out
}

function boot_vm() {
# boot QEMU VM, C-a x to quit. VM port 22 is forwarded to host:2222
echo "Launching VM from image 'vm-base', type 'C-a x' to quit."
echo "Login as user/pass: 'test/${1}': ssh -p 8888 test@localhost"
azldev image boot vm-base --test-password "${1}"
}

if [[ "$image_type" == "container" ]] ; then
build_container_image
elif [[ "$image_type" == "vm" || "$image_type" == "vm-boot" ]] ; then
# You may need this cleanup until azldev is fixed:
# sudo rm -rf $(git rev-parse --show-toplevel)/base/out/images
build_vm_image
if [[ "$image_type" == "vm-boot" ]] ; then
boot_vm "$(mktemp -u XXXXXX)"
fi
else
echo "Unknown image type '$image_type'"
fi
Loading