diff --git a/.gitignore b/.gitignore index cfb359c9..e807c552 100644 --- a/.gitignore +++ b/.gitignore @@ -345,4 +345,4 @@ azure-slurm-install/dist azure-slurm-install/docker/ .DS_Store .build.log -azure-slurm-install/AzureCA.pem +azure-slurm-install/AzureCA*.pem diff --git a/README.md b/README.md index 38935c32..46aeb1c0 100644 --- a/README.md +++ b/README.md @@ -559,7 +559,7 @@ The following table describes the Slurm-specific configuration options you can t | slurm.accounting.storageloc | Optional when `slurm.accounting.enabled = true`. Database name to store slurm accounting records | | slurm.accounting.user | Required when `slurm.accounting.enabled = true`. User for Slurm DBD admin | | slurm.accounting.password | Required when `slurm.accounting.enabled = true`. Password for Slurm DBD admin | -| slurm.accounting.certificate_url | Required when `slurm.accounting.enabled = true`. Url to fetch SSL Certificate for authentication to DB. Use AzureCA.pem (embedded) for use with deprecated MariaDB instances. | +| slurm.accounting.certificate | Optional user specified SSL certificate for DB Authentication. Default is combined SSL certs for Azure Database for MySQL Server | | slurm.additional.config | Any additional lines to add to slurm.conf | | slurm.ha_enabled | Default: `false`. Setting to deploy with an additional HA node | | slurm.launch_parameters | Default: `use_interactive_step`. Deploy Slurm with Launch Parameters (comma delimited) | diff --git a/azure-slurm-install/install.py b/azure-slurm-install/install.py index 4c7f1adc..e89eeefe 100644 --- a/azure-slurm-install/install.py +++ b/azure-slurm-install/install.py @@ -9,9 +9,8 @@ import installlib as ilib from typing import Dict, Optional -# Legacy: used for connecting to Azure MariaDB, which is deprecated. -LOCAL_AZURE_CA_PEM = "AzureCA.pem" - +# Combined Certs needed to connect to Azure Database for MySQL Server +COMBINED_CERTS = "AzureCA_4.0.8.pem" class InstallSettings: def __init__(self, config: Dict, platform_family: str, mode: str) -> None: @@ -98,8 +97,9 @@ def __init__(self, config: Dict, platform_family: str, mode: str) -> None: self.acct_user: Optional[str] = config["slurm"]["accounting"].get("user") self.acct_pass: Optional[str] = config["slurm"]["accounting"].get("password") self.acct_url: Optional[str] = config["slurm"]["accounting"].get("url") - self.acct_cert_url: Optional[str] = config["slurm"]["accounting"].get("certificate_url") + self.custom_acct_cert: Optional[str] = config["slurm"]["accounting"].get("certificate") self.acct_storageloc :Optional[str] = config["slurm"]["accounting"].get("storageloc") + self.acct_cert_filename = "CustomCA.pem" if self.custom_acct_cert else COMBINED_CERTS self.use_nodename_as_hostname = config["slurm"].get( "use_nodename_as_hostname", False @@ -393,30 +393,25 @@ def _accounting_primary(s: InstallSettings) -> None: """, ) - # Previously this was required when connecting to any Azure MariaDB instance. - # Which is why we shipped with LOCAL_AZURE_CA_PEM. - if s.acct_cert_url and s.acct_cert_url != LOCAL_AZURE_CA_PEM: - logging.info(f"Downloading {s.acct_cert_url} to {s.config_dir}/AzureCA.pem") - subprocess.check_call( - [ - "wget", - "-O", - f"{s.config_dir}/AzureCA.pem", - s.acct_cert_url, - ] - ) - ilib.chown( - f"{s.config_dir}/AzureCA.pem", owner=s.slurm_user, group=s.slurm_grp - ) - ilib.chmod(f"{s.config_dir}/AzureCA.pem", mode="0600") - elif s.acct_cert_url and s.acct_cert_url == LOCAL_AZURE_CA_PEM: - ilib.copy_file( - LOCAL_AZURE_CA_PEM, - f"{s.config_dir}/AzureCA.pem", + # Always copy the bundled certificate + ilib.copy_file( + COMBINED_CERTS, + f"{s.config_dir}/{COMBINED_CERTS}", + owner=s.slurm_user, + group=s.slurm_grp, + mode="0600", + ) + #Install custom SSL cert if specified + if s.custom_acct_cert: + cert_path = f"{s.config_dir}/{s.acct_cert_filename}" + logging.info(f"Saving custom SSL cert to {cert_path}") + ilib.file( + cert_path, owner=s.slurm_user, group=s.slurm_grp, mode="0600", - ) + content=s.custom_acct_cert, + ) # Configure slurmdbd.conf ilib.template( @@ -430,9 +425,7 @@ def _accounting_primary(s: InstallSettings) -> None: "dbuser": s.acct_user or "root", "dbdhost": s.hostname, "storagepass": f"StoragePass={s.acct_pass}" if s.acct_pass else "#StoragePass=", - "storage_parameters": "StorageParameters=SSL_CA=/etc/slurm/AzureCA.pem" - if s.acct_cert_url - else "#StorageParameters=", + "storage_parameters": f"StorageParameters=SSL_CA=/etc/slurm/{s.acct_cert_filename}", "slurmver": s.slurmver, "storageloc": s.acct_storageloc or f"{s.slurm_db_cluster_name}_acct_db", "auth_alt_type": "AuthAltTypes=auth/jwt" if s.jwt_available else "", @@ -458,16 +451,21 @@ def _accounting_all(s: InstallSettings) -> None: """ Perform linking and enabling of slurmdbd """ - # This used to be required for all installations, but it is - # now optional, so only create the link if required. - original_azure_ca_pem = f"{s.config_dir}/AzureCA.pem" + # Always link the bundled certificate to /etc/slurm in addition to user specified custom SSL certificate ilib.link( - f"{s.config_dir}/AzureCA.pem", - "/etc/slurm/AzureCA.pem", + f"{s.config_dir}/{COMBINED_CERTS}", + f"/etc/slurm/{COMBINED_CERTS}", owner=s.slurm_user, group=s.slurm_grp, ) + if s.custom_acct_cert: + ilib.link( + f"{s.config_dir}/{s.acct_cert_filename}", + f"/etc/slurm/{s.acct_cert_filename}", + owner=s.slurm_user, + group=s.slurm_grp, + ) # Link shared slurmdbd.conf to real config file location ilib.link( f"{s.config_dir}/slurmdbd.conf", diff --git a/azure-slurm-install/package.py b/azure-slurm-install/package.py index f5898865..8c9969f7 100644 --- a/azure-slurm-install/package.py +++ b/azure-slurm-install/package.py @@ -4,6 +4,7 @@ import sys import tarfile import requests +import tempfile from typing import Optional def execute() -> None: @@ -58,6 +59,54 @@ def _add(name: str, path: Optional[str] = None, mode: Optional[int] = None) -> N with open(path, "rb") as fr: tf.addfile(tarinfo, fr) + def _create_combined_certs() -> None: + """ + Download and combine three SSL certificates required for Azure MySQL: + 1. DigiCert Global Root CA + 2. DigiCert Global Root G2 + 3. Microsoft RSA Root Certificate Authority 2017 (converted from DER to PEM) + """ + cert_urls = { + "digicert_root_ca": "https://cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem", + "digicert_root_g2": "https://cacerts.digicert.com/DigiCertGlobalRootG2.crt.pem", + "microsoft_rsa_2017": "https://www.microsoft.com/pkiops/certs/Microsoft%20RSA%20Root%20Certificate%20Authority%202017.crt" + } + + combined_pem = "" + + with tempfile.TemporaryDirectory() as tmpdir: + # Download DigiCert Global Root CA + digicert_ca_path = os.path.join(tmpdir, "DigiCertGlobalRootCA.crt.pem") + _download(cert_urls["digicert_root_ca"], digicert_ca_path) + with open(digicert_ca_path, "r") as f: + combined_pem += f.read() + "\n" + + # Download DigiCert Global Root G2 + digicert_g2_path = os.path.join(tmpdir, "DigiCertGlobalRootG2.crt.pem") + _download(cert_urls["digicert_root_g2"], digicert_g2_path) + with open(digicert_g2_path, "r") as f: + combined_pem += f.read() + "\n" + + # Download Microsoft RSA 2017 (DER format) + microsoft_der_path = os.path.join(tmpdir, "MicrosoftRSA2017.crt") + _download(cert_urls["microsoft_rsa_2017"], microsoft_der_path) + + # Convert DER to PEM + microsoft_pem_path = os.path.join(tmpdir, "MicrosoftRSA2017.pem") + subprocess.check_call([ + "openssl", "x509", + "-inform", "DER", + "-in", microsoft_der_path, + "-out", microsoft_pem_path + ]) + with open(microsoft_pem_path, "r") as f: + combined_pem += f.read() + "\n" + cert_name = f"AzureCA_{version}.pem" + # Write combined certificates to AzureCA_{version}.pem + with open(cert_name, "w") as f: + f.write(combined_pem) + _add(cert_name,cert_name) + #Download EPEL for ver in ["8", "9"]: url = f"https://dl.fedoraproject.org/pub/epel/epel-release-latest-{ver}.noarch.rpm" @@ -95,6 +144,7 @@ def _add(name: str, path: Optional[str] = None, mode: Optional[int] = None) -> N _download(pyxis_url, pyxis_dest) _add(pyxis_dest, pyxis_dest) + _create_combined_certs() _add("install.sh", "install.sh", mode=os.stat("install.sh")[0]) _add("install_logging.conf", "conf/install_logging.conf") _add("installlib.py", "installlib.py") @@ -108,7 +158,6 @@ def _add(name: str, path: Optional[str] = None, mode: Optional[int] = None) -> N _add("azurelinux.sh", "azurelinux.sh", 600) _add("imex_prolog.sh", "imex_prolog.sh", 600) _add("imex_epilog.sh", "imex_epilog.sh", 600) - _add("AzureCA.pem", "AzureCA.pem") _add("suse.sh", "suse.sh", 600) _add("start-services.sh", "start-services.sh", 555) _add("capture_logs.sh", "capture_logs.sh", 755) diff --git a/templates/slurm.txt b/templates/slurm.txt index 8fec765f..74f94231 100644 --- a/templates/slurm.txt +++ b/templates/slurm.txt @@ -38,7 +38,7 @@ Autoscale = $Autoscale slurm.accounting.url = $configuration_slurm_accounting_url slurm.accounting.user = $configuration_slurm_accounting_user slurm.accounting.password = $configuration_slurm_accounting_password - slurm.accounting.certificate_url = $configuration_slurm_accounting_certificate_url + slurm.accounting.certificate = $configuration_slurm_accounting_custom_certificate slurm.accounting.storageloc = $configuration_slurm_accounting_storageloc slurm.additional.config = $additional_slurm_config slurm.ha_enabled = $configuration_slurm_ha_enabled @@ -799,15 +799,20 @@ Order = 20 ParameterType = Password Conditions.Excluded := configuration_slurm_accounting_enabled isnt true - [[[parameter configuration_slurm_accounting_certificate_url]]] - Label = SSL Certificate URL - Description = URL to fetch SSL certificate for authentication to DB. Use AzureCA.pem (embedded) for use with deprecated MariaDB instances. + [[[parameter configuration_slurm_accounting_custom_certificate_enabled]]] + Label = Custom SSL Certificate + Description = Enable to add custom SSL Certificate for DB Authentication. Default installs combined certs needed for Azure Database for MySQL. + DefaultValue = false + Widget.Plugin = pico.form.BooleanCheckBox + Widget.Label = Use custom SSL certificate for connecting to DB Conditions.Excluded := configuration_slurm_accounting_enabled isnt true - ParameterType = StringList - Config.Plugin = pico.form.Dropdown - Config.FreeForm = true - Config.Entries := {[Value=""], [Value="AzureCA.pem"]} - DefaultValue = "" + + [[[parameter configuration_slurm_accounting_custom_certificate]]] + Label = Custom SSL Certificate for DB Authentication + Description = Content of Custom SSL Certificate for DB Authentication + Conditions.Excluded := configuration_slurm_accounting_enabled isnt true || configuration_slurm_accounting_custom_certificate_enabled isnt true + Conditions.Required := configuration_slurm_accounting_custom_certificate_enabled is true + ParameterType = Text [[[parameter EnableTerminateNotification]]] Label = Enable Termination notifications diff --git a/util/build.sh b/util/build.sh index 5d2dadee..60cf2e55 100755 --- a/util/build.sh +++ b/util/build.sh @@ -22,7 +22,6 @@ if [ ! -e $SOURCE/blobs ]; then mkdir $SOURCE/blobs fi -wget -k -O $SOURCE/azure-slurm-install/AzureCA.pem https://github.com/Azure/cyclecloud-slurm/releases/download/2.7.3/AzureCA.pem # ls slurm/install/slurm-pkgs/*.rpm > /dev/null || (echo you need to run docker-rpmbuild.sh first; exit 1) # ls slurm/install/slurm-pkgs/*.deb > /dev/null || (echo you need to run docker-rpmbuild.sh first; exit 1)