xcat-core
xcat-core copied to clipboard
Add support for HMAC-SHA256 to ddns.pm and dhcp.pm, for xcat_key.
I know xCAT doesn't officially support FIPS, but our site runs with FIPS and I wanted to provide a patch to ddns.pm I put together that will allow makedns and named/dhcp to work with an HMAC-SHA256 xcat_key, which is FIPS compliant, instead of the default HMAC-MD5 one. MD5 is a pretty ancient method, and SHA256 support at this point (even for non FIPS sites) isn't unreasonable.
I'd like to request incorporating this into a future release of xCAT, as it's only a total of 4 lines of code changes and doesn't require any other updates to support "makedns" with HMAC-256 (at least that I've found).
--- ddns.pm-git 2022-05-13 05:45:43.859153040 -0400
+++ ddns.pm 2022-05-16 08:31:03.999754671 -0400
@@ -1358,7 +1358,7 @@
$ctx->{privkey} = encode_base64(genpassword(32));
chomp($ctx->{privkey});
}
- push @newnamed, "key xcat_key {\n", "\talgorithm hmac-md5;\n", "\tsecret \"" . $ctx->{privkey} . "\";\n", "};\n\n";
+ push @newnamed, "key xcat_key {\n", "\talgorithm hmac-sha256;\n", "\tsecret \"" . $ctx->{privkey} . "\";\n", "};\n\n";
$ctx->{restartneeded} = 1;
}
}
@@ -1550,6 +1550,7 @@
}
my $resolver = Net::DNS::Resolver->new(nameservers => [$ip]);
+ my $keyrr = new Net::DNS::RR('xcat_key. IN KEY 512 3 163 '.$ctx->{privkey});
my $entry;
my $numreqs = 300; # limit to 300 updates in a payload, something broke at 644 on a certain sample, choosing 300 for now
my $update = Net::DNS::Update->new($zone);
@@ -1564,7 +1565,7 @@
# sometimes even the xcat_key is correct, but named still replies NOTAUTH, so retry
for (1 .. 3) {
- $update->sign_tsig("xcat_key", $ctx->{privkey});
+ $update->sign_tsig($keyrr);
$numreqs = 300;
my $reply = $resolver->send($update);
if ($reply) {
@@ -1586,7 +1587,7 @@
if ($numreqs != 300) { #either no entries at all to begin with or a perfect multiple of 300
# sometimes even the xcat_key is correct, but named still replies NOTAUTH, so retry
for (1 .. 3) {
- $update->sign_tsig("xcat_key", $ctx->{privkey});
+ $update->sign_tsig($keyrr);
my $reply = $resolver->send($update);
if ($reply) {
if ($reply->header->rcode eq 'NOTAUTH') {
--- dhcp.pm-git 2022-05-13 08:47:53.109714617 -0400
+++ dhcp.pm 2022-05-13 07:57:03.869429602 -0400
@@ -2963,7 +2963,7 @@
# push @dhcp6conf, "update-static-leases on;\n";
push @dhcp6conf, "omapi-port 7912;\n"; #Enable omapi...
push @dhcp6conf, "key xcat_key {\n";
- push @dhcp6conf, " algorithm hmac-md5;\n";
+ push @dhcp6conf, " algorithm hmac-sha256;\n";
my $passtab = xCAT::Table->new('passwd', -create => 1);
(my $passent) =
$passtab->getAttribs({ key => 'omapi', username => 'xcat_key' }, 'password');
@bviviano Thank you for the suggestion to improve xCAT support for FIPS. Contributions like this will improve xCAT's ability to function correctly with FIPS enabled.
1.) Would you be willing to volunteer to take a more active role in the project for activities related to FIPS, such as testing, contributing code improvements, and assisting other users with issues related to FIPS?
2.) Can you provide some unit test results showing how the suggested change can be tested? Also, how did you debug this problem initially?
@besawn,
1.) Would you be willing to volunteer to take a more active role in the project for activities related to FIPS, such as testing, contributing code improvements, and assisting other users with issues related to FIPS?
Sure, I'm glad to assist where I can, but we only use the more traditional components on xCAT, for bare metal provisioning. We don't have anything setup for docker, VM's, etc.
Can you provide some unit test results showing how the suggested change can be tested?
In this specific case, the patch I provided should work on any modern Linux system, so it doesn't have to be FIPS enabled. Unit testing should be in line with anything you would normally do to test ddns.pm or dhcp.pm.
If you wanted to do any specific FIPS testing, you'd have to have a FIPS enabled solution (i.e. system. docker server, etc). So I don't know how feasible that is with the current automated test setup used by xcat-core.
Also, how did you debug this problem initially?
When running makedns, after doing the initial xCAT setup, I got the following error
[root@smtools ~]# /opt/xcat/sbin/makedns -n
Warning: SELINUX is not disabled. The makedns command will not be able to generate a complete DNS setup. Disable SELINUX and run the command again.
Handling smtools in /etc/hosts.
Handling r1n03-ib0 in /etc/hosts.
Handling r1n04-bmc in /etc/hosts.
Handling switch0 in /etc/hosts.
Handling smtools-ib0 in /etc/hosts.
Handling r1n02-ib0 in /etc/hosts.
Handling loghost1 in /etc/hosts.
Handling storage1-ib0 in /etc/hosts.
Handling r1n03 in /etc/hosts.
Handling localhost in /etc/hosts.
Handling r1n02-bmc in /etc/hosts.
Handling r1n01-ib0 in /etc/hosts.
Handling switch1 in /etc/hosts.
Handling localhost in /etc/hosts.
Handling r1n03-bmc in /etc/hosts.
Handling r1n01-bmc in /etc/hosts.
Handling r1n02 in /etc/hosts.
Handling r1n04-ib0 in /etc/hosts.
Handling r1n01 in /etc/hosts.
Handling r1n04 in /etc/hosts.
Getting reverse zones, this may take several minutes for a large cluster.
Completed getting reverse zones.
Updating zones.
Completed updating zones.
Restarting named
Error: [smtools]: failed to start named.
Upon investigating the error provided by named, systemctl status showed
[root@smtools ~]# systemctl status named
● named.service - Berkeley Internet Name Domain (DNS)
Loaded: loaded (/usr/lib/systemd/system/named.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Tue 2022-05-17 08:18:01 EDT; 1min 41s ago
Process: 97142 ExecStop=/bin/sh -c /usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID (code=exited, sta>
Process: 97635 ExecStartPre=/bin/bash -c if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf ->
Main PID: 96777 (code=exited, status=0/SUCCESS)
May 17 08:18:01 smtools.hesc.epa.gov systemd[1]: Starting Berkeley Internet Name Domain (DNS)...
May 17 08:18:01 smtools.hesc.epa.gov bash[97636]: /etc/named.conf:21: disabled algorithm 'hmac-md5'
May 17 08:18:01 smtools.hesc.epa.gov systemd[1]: named.service: Control process exited, code=exited status=1
May 17 08:18:01 smtools.hesc.epa.gov systemd[1]: named.service: Failed with result 'exit-code'.
May 17 08:18:01 smtools.hesc.epa.gov systemd[1]: Failed to start Berkeley Internet Name Domain (DNS).
The key line being /etc/named.conf:21: disabled algorithm 'hmac-md5'. MD5 based network algorithms in named are disabled on RHEL systems with FIPS enabled per the FIPS crypto-policy
[root@smtools ~]# cat /usr/share/crypto-policies/FIPS/bind.txt
disable-algorithms "." {
RSAMD5;
RSASHA1;
NSEC3RSASHA1;
DSA;
};
disable-ds-digests "." {
SHA-1;
GOST;
};
Once I knew what the issue was, I investigated what FIPS compliant algorithms where available to named, modified /etc/named.conf manually with a compliant algorithm so I could get named started, then used nsupdate to make changes to the xCAT defined zones, using xcat_key. Once I found a combination that worked while FIPS was enabled, I went about digging into Net::DNS to figure out what I needed to do update ddns.pm to match.
The key thing I've found to keep in mind when it comes to FIPS is, anything that goes out over the network needs to be FIPS level encryption, but not everything you run needs on the host has to be FIPS. For example, I can use md5sum no problem:
[root@smtools perl]# fips-mode-setup --check
FIPS mode is enabled.
[root@smtools ~]# md5sum /etc/hosts
416588a4a0747ef944e591129bf5f9ac /etc/hosts
[root@smtools ~]#
So, most xCAT modules using Digest::MD5 for local file checking should be fine (like in copycds or packimage). It's only if it goes out on the Network (like xcat_key in named) do you have a problem.
For example, we don't currently have any BMC's that are FIPS compliant, but our next cluster will have BMC's with FIPS level encryption options and I expect I'll have issues with IPMI.pm that I'll need to look more closely at.
I'm providing an updated patch to ddns.pm that works in concert with the one I provided on #7181 for dhcp.pm, to allow you to specify any of the following via the site table
- HMAC-MD5
- HMAC-SHA1
- HMAC-SHA224
- HMAC-SHA256
- HMAC-SHA384
- HMAC-SHA512
The default is HMAC-MD5, to maintain backwards compatibility.
--- ddns.pm-orig 2022-05-19 07:15:24.278501564 -0400
+++ ddns.pm 2022-05-23 09:28:28.982414574 -0400
@@ -1345,13 +1345,20 @@
}
}
+ # Get HMAC algorithum from site table, if set
+ my $omapialgorithm = "HMAC-MD5";
+ my @omapia=xCAT::TableUtils->get_site_attribute("omapi-algorithm");
+ if ($omapia[0]){
+ $omapialgorithm=$omapia[0];
+ }
+
unless ($slave) {
unless ($gotkey) {
unless ($ctx->{privkey}) { #need to generate one
$ctx->{privkey} = encode_base64(genpassword(32));
chomp($ctx->{privkey});
}
- push @newnamed, "key xcat_key {\n", "\talgorithm hmac-md5;\n", "\tsecret \"" . $ctx->{privkey} . "\";\n", "};\n\n";
+ push @newnamed, "key xcat_key {\n", "\talgorithm $omapialgorithm;\n", "\tsecret \"" . $ctx->{privkey} . "\";\n", "};\n\n";
$ctx->{restartneeded} = 1;
}
}
@@ -1542,6 +1549,25 @@
return 1;
}
+ # Get HMAC algorithum from site table, if set
+ my $omapialgorithm = "HMAC-MD5";
+ my @omapia=xCAT::TableUtils->get_site_attribute("omapi-algorithm");
+ if ($omapia[0]){
+ $omapialgorithm=$omapia[0];
+ }
+ my $RR_key_type=157; # Default to MD5
+ if ($omapialgorithm =~ /HMAC-SHA1/i) {
+ $RR_key_type=161;
+ } elsif ($omapialgorithm =~ /HMAC-SHA224/i) {
+ $RR_key_type=162;
+ } elsif ($omapialgorithm =~ /HMAC-SHA256/i) {
+ $RR_key_type=163;
+ } elsif ($omapialgorithm =~ /HMAC-SHA384/i) {
+ $RR_key_type=164;
+ } elsif ($omapialgorithm =~ /HMAC-SHA512/i) {
+ $RR_key_type=165;
+ }
+ my $keyrr = new Net::DNS::RR('xcat_key. IN KEY 512 3 '.$RR_key_type.' '.$ctx->{privkey});
my $resolver = Net::DNS::Resolver->new(nameservers => [$ip]);
my $entry;
my $numreqs = 300; # limit to 300 updates in a payload, something broke at 644 on a certain sample, choosing 300 for now
@@ -1557,7 +1583,7 @@
# sometimes even the xcat_key is correct, but named still replies NOTAUTH, so retry
for (1 .. 3) {
- $update->sign_tsig("xcat_key", $ctx->{privkey});
+ $update->sign_tsig($keyrr);
$numreqs = 300;
my $reply = $resolver->send($update);
if ($reply) {
@@ -1579,7 +1605,7 @@
if ($numreqs != 300) { #either no entries at all to begin with or a perfect multiple of 300
# sometimes even the xcat_key is correct, but named still replies NOTAUTH, so retry
for (1 .. 3) {
- $update->sign_tsig("xcat_key", $ctx->{privkey});
+ $update->sign_tsig($keyrr);
my $reply = $resolver->send($update);
if ($reply) {
if ($reply->header->rcode eq 'NOTAUTH') {