CentOS 7.9 on Azure User Guide
Overview
This guide covers the deployment and configuration of CentOS 7.9 (CentOS Linux release 7.9.2009, the final CentOS 7 release) on Microsoft Azure, using cloudimg's CentOS 7.9 virtual machine image from the Azure Marketplace.
CentOS Linux is a community rebuild of Red Hat Enterprise Linux, binary compatible with RHEL 7. This image is for existing CentOS 7 workloads: software that is still certified only on the CentOS 7 / RHEL 7 platform, kept running while you move it to a supported distribution.
Every command and every output in this guide was run on a virtual machine deployed from the public Marketplace image (image version 3.0.0), as the azureuser account a customer gets.
End of life notice: read this first
CentOS Linux 7 reached end of life on 30 June 2024. The CentOS Project publishes no further updates for it, security updates included (CentOS Project, Red Hat). The final CentOS 7 packages were archived on vault.centos.org, and nothing newer will ever be released. Consequently:
- This image was patched when it was built (its running kernel is
3.10.0-1160.66.1.el7). The CentOS 7 updates published after that build, up to the last ones in the vault, are not applied: a fresh virtual machine has about 80 newer packages waiting, including kernel3.10.0-1160.119.1.el7. Step 5 applies them. - Even with every vault package applied, the system will carry vulnerabilities that can never be fixed by updating CentOS 7, because upstream ships nothing further.
- Plan a migration to a supported distribution, such as AlmaLinux, Rocky Linux, CentOS Stream or a current RHEL, for any workload that must remain secure.
The image's CentOS repositories still use the original mirrorlist.centos.org service, which was retired at end of life. Step 4 points them at the CentOS 7.9.2009 vault, which is the only lasting source of CentOS 7 packages. Do that first on every new virtual machine.
What's included
- CentOS Linux 7.9.2009 (Core), binary compatible with RHEL 7, on the 3.10.0 el7 kernel
- Azure Linux Agent (
waagent, WALinuxAgent 2.9.1.1) active and enabled, plus cloud-init 19.4, for Azure provisioning - Azure CLI 2.38.1 (
az) and Python 3.6.8 (python3) preinstalled - Chronyd for NTP time synchronisation
- EPEL 7 and the Microsoft Azure CLI repository configured, alongside the CentOS base, updates and extras repositories
- firewalld installed (disabled; see Step 8)
- Gen1 Hyper V virtual machine (BIOS boot)
- 24/7 cloudimg support
Platform: Microsoft Azure (Gen1 Hyper V)
Default user: azureuser (or the administrator name you choose at create time)
Security posture
This image ships with no default password, and SSH accepts keys only:
PasswordAuthenticationisnoin/etc/ssh/sshd_config, so every login is by key.- The key that logs you in is the public key you supply when you create the virtual machine. Azure installs it for your administrator user at first boot.
- The root password is locked, and the
centosaccount that the image also carries is locked and has no SSH key. - SSH logins as
rootare refused with a message:/root/.ssh/authorized_keysholds entries that only printPlease login as the user "azureuser" rather than the user "root".and close the connection. Two of those entries were left in the image from before it was captured; they carry the same command, so they cannot open a shell. Step 6 shows how to remove them and turn root login off in the SSH daemon as well. - SELinux is disabled on this image (
SELINUX=disabledin/etc/selinux/config).
Prerequisites
Before deploying this image, ensure you have:
- An active Microsoft Azure subscription
- Access to the Azure Portal or the Azure CLI
- An SSH key pair for Linux virtual machine access
- Familiarity with Azure virtual machine management
Choose a virtual machine size that suits your workload. The image is Gen1 (BIOS boot), so pick a size that supports Gen1 virtual machines.
Step 1: Deploy the Virtual Machine
Option A: Azure Portal
- Navigate to the Azure Marketplace and search for "CentOS 7.9 cloudimg"
- Open the CentOS 7.9 listing and choose Get it now, then Create
- Configure the basics:
- Subscription: Select your Azure subscription
- Resource Group: Create new or select existing
- Virtual Machine Name: Enter a name for your VM
- Region: Select your preferred Azure region
- Size: Select a size for your workload
- Under Administrator Account, select SSH public key and enter your key
- Under Inbound Port Rules, allow SSH (port 22), ideally from your own network only
- Click Review + Create, then Create
Option B: Azure CLI
The image carries a Marketplace purchase plan, so accept its terms once per subscription, then create the virtual machine. Replace <your-vm-size> with the size you chose:
az vm image terms accept --urn cloudimg1647283583153:3119f0ab-69f5-4bcf-a596-73f9e705f670:3119f0ab-69f5-4bcf-a596-73f9e705f670:latest
az vm create \
--resource-group myResourceGroup \
--name my-centos-7-9-vm \
--image cloudimg1647283583153:3119f0ab-69f5-4bcf-a596-73f9e705f670:3119f0ab-69f5-4bcf-a596-73f9e705f670:latest \
--size <your-vm-size> \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
The offer and plan are both named by the same identifier (3119f0ab-69f5-4bcf-a596-73f9e705f670), which is why it appears twice in the URN.
Step 2: Connect via SSH
Run these on your own workstation, not on the VM. Find the public IP, then connect:
az vm show --resource-group myResourceGroup --name my-centos-7-9-vm --show-details --query publicIps -o tsv
ssh azureuser@<vm-ip>
There is no password to enter. If SSH asks you for one, the key you supplied at create time is not the key your client is offering.
Your first login prints a Last login: line dated 17 November 2023. That record was left in the image from before it was captured; it is not a login to your virtual machine. From the second login on, the line shows your own previous session.
If your workstation sends a locale that CentOS 7 does not have (for example C.UTF-8), bash prints setlocale: LC_ALL: cannot change locale. Connect with a locale the image has, such as LC_ALL=en_US.UTF-8 ssh azureuser@<vm-ip>.
Step 3: Confirm the release
Check that the machine is the CentOS Linux 7.9.2009 release you expect:
cat /etc/centos-release
grep -E '^(NAME|VERSION|ID|VERSION_ID)=' /etc/os-release
uname -rm
Expected output on a fresh virtual machine:
CentOS Linux release 7.9.2009 (Core)
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
VERSION_ID="7"
3.10.0-1160.66.1.el7.x86_64 x86_64
After Step 5 and a reboot, uname -r reports 3.10.0-1160.119.1.el7.x86_64, the last CentOS 7 kernel.
Step 4: Point yum at the CentOS vault
The CentOS base, updates and extras repositories in /etc/yum.repos.d/CentOS-Base.repo still use mirrorlist=http://mirrorlist.centos.org/.... That service was retired at end of life, so yum falls back to a list of mirrors cached in the image, and most of those mirrors no longer carry CentOS 7 (they return 404). The vault is the lasting home of the final packages. Switch the repositories to it:
sudo cp -a /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.orig
sudo sed -i -e 's/^mirrorlist=/#mirrorlist=/' \
-e 's|^#baseurl=http://mirror.centos.org/centos/$releasever|baseurl=https://vault.centos.org/7.9.2009|' \
/etc/yum.repos.d/CentOS-Base.repo
sudo yum clean all
grep '^baseurl' /etc/yum.repos.d/CentOS-Base.repo
yum repolist enabled
Expected output of the grep (the fourth line is the centosplus repository, which stays disabled):
baseurl=https://vault.centos.org/7.9.2009/os/$basearch/
baseurl=https://vault.centos.org/7.9.2009/updates/$basearch/
baseurl=https://vault.centos.org/7.9.2009/extras/$basearch/
baseurl=https://vault.centos.org/7.9.2009/centosplus/$basearch/
yum repolist enabled then lists five enabled repositories: azure-cli, base, epel, extras and updates. To confirm where each enabled repository is fetched from:
yum -v repolist enabled 2>/dev/null | grep -i '^Repo-baseurl'
base, updates and extras report https://vault.centos.org/7.9.2009/..., azure-cli reports packages.microsoft.com, and epel reports a mirror of the Fedora archive (EPEL 7 is archived too).
Step 5: Apply the final CentOS 7 updates
With the vault in place, see what is waiting:
sudo yum -q check-update; echo "check-update exit: $?"
On a fresh virtual machine, check-update lists about 80 packages and exits 100 (which means "updates are available"), among them kernel 3.10.0-1160.119.1.el7, glibc, openssl, openssh, sudo, systemd and azure-cli. Apply them and reboot onto the new kernel:
sudo yum -y update
sudo reboot
After the reboot, sudo yum -q check-update; echo "check-update exit: $?" prints check-update exit: 0: nothing newer exists in the vault. That is the end of the CentOS 7 lifecycle, not a guarantee of security. No further security updates will ever be published upstream.
While the kernel installs you may see /usr/lib/dracut/modules.d/95involflt/installkernel: line 6: /tmp/MobSvcInstaller/ASR/Vx/bin/check_drivers.sh: No such file or directory. It comes from a replication agent left in the image (see Troubleshooting) and does not stop the update: the new kernel boots normally.
Step 6: Verify the security posture
Confirm SSH is key only, root is locked and SELinux's state:
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication) '
sudo passwd -S root
getenforce
Expected output on a fresh virtual machine:
permitrootlogin yes
pubkeyauthentication yes
passwordauthentication no
root LK 1969-12-30 0 99999 7 -1 (Password locked.)
Disabled
permitrootlogin yes is the CentOS 7 default; root still cannot log in, because its password is locked and every entry in /root/.ssh/authorized_keys only prints the "Please login as the user" message. To remove the two entries left in the image and turn root login off in the SSH daemon too:
sudo truncate -s 0 /root/.ssh/authorized_keys
sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
echo "PermitRootLogin no" | sudo tee -a /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl restart sshd
sudo sshd -T | grep '^permitrootlogin'
The last command then prints permitrootlogin no. Keep your current session open until you have checked that a new ssh azureuser@<vm-ip> still works.
Step 7: Verify Azure integration
Confirm the Azure Linux Agent, cloud-init and time synchronisation are healthy:
systemctl is-active waagent
systemctl is-enabled waagent
cloud-init --version
sudo cloud-init status
systemctl is-active chronyd
timedatectl | grep 'Time zone'
Expected output:
active
enabled
/usr/bin/cloud-init 19.4
status: done
active
Time zone: America/New_York (EST, -0500)
(The zone shows EDT, -0400 in summer.) waagent is what lets Azure provision your SSH key, run extensions and report VM health, so it should always be active and enabled.
Run cloud-init status with sudo on this image. Without sudo, CentOS 7's cloud-init 19.4 crashes with NameError: global name 'PermissionError' is not defined when it cannot read its root only status file. That is a bug in the command's error handling only and is harmless: provisioning ran (cloud-init created your user and installed your SSH key).
The image's clock zone is America/New_York, so local timestamps and log times are US Eastern. To use UTC (or your own zone):
sudo timedatectl set-timezone UTC
The preinstalled tools are ready to use:
python3 --version
az version
python3 reports Python 3.6.8 and az version reports "azure-cli": "2.38.1" (Step 5 upgrades it to 2.38.2). Sign in with az login before using the Azure CLI against your subscription.
Step 8: Networking and the firewall
The Azure Network Security Group is the control plane for inbound and outbound traffic, and it is the first and usually the only place you need to open a port. The image needs a single inbound port, SSH on 22.
Confirm what is listening before you open anything:
sudo ss -tlnp
The only externally reachable listener is sshd on port 22. You will also see master (postfix) bound to 127.0.0.1:25 and [::1]:25: the local mail transport, reachable only from the machine itself.
firewalld is installed but disabled. If your policy requires a host firewall as well, enable it and keep SSH open so you do not lock yourself out:
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
--list-services then prints dhcpv6-client ssh. (firewalld's default zone already allows SSH, so --add-service=ssh may answer Warning: ALREADY_ENABLED: ssh.)
Server Components
| Component | Version | Notes |
|---|---|---|
| CentOS Linux | 7.9.2009 (Core) | End of life 30 June 2024 |
| Linux kernel | 3.10.0-1160.66.1.el7 | 3.10.0-1160.119.1.el7 after Step 5 |
| Azure Linux Agent | WALinuxAgent 2.9.1.1 | waagent, active and enabled |
| cloud-init | 19.4 | Use sudo cloud-init status |
| Azure CLI | 2.38.1 | az, from packages.microsoft.com |
| Python 3 | 3.6.8 | python3 |
| OpenSSH server | 7.4p1 | Key only login |
| chrony | 3.4 | chronyd, active |
| firewalld | 0.6.3 | Installed, disabled |
Filesystem Layout
| Mount Point | Size | Description |
|---|---|---|
| / | 38 GB | Root filesystem (ext4, /dev/sda2) |
| /boot | 2 GB | Kernel files (ext4, /dev/sda1) |
| /mnt | varies | Azure temporary resource disk; its contents are lost when the VM is deallocated |
The 50 GB OS disk also holds a 10 GB partition (/dev/sda3) formatted as swap. It is not in /etc/fstab and is not used; the image runs without swap. Because that partition sits after the root partition, / cannot simply be grown into the rest of the disk. If you need more space, attach a data disk and mount it.
Scripts and Log Files
| Path | Purpose |
|---|---|
/stage/scripts/initial_boot_update.sh |
Runs at every boot from root's crontab (see On Startup) |
/stage/scripts/initial_boot_update.log |
Output of that script; it also holds entries from boots before the image was captured |
/var/log/cloud-init.log |
cloud-init provisioning log |
/var/log/waagent.log |
Azure Linux Agent log |
/var/log/yum.log |
Packages installed and updated by yum |
On Startup
Root's crontab runs /stage/scripts/initial_boot_update.sh at every boot (@reboot). The script runs:
yum -y update --security --exclude=kernel*
On CentOS this applies nothing: CentOS repositories publish no security advisory metadata, so yum --security reports No packages needed for security and leaves every package as it is. Treat Step 5 as the way to update this image. To stop the boot time job, remove its line with sudo crontab -e.
Common Use Cases
- Running software that is only certified on the CentOS 7 / RHEL 7 platform, while you re platform it
- Lift and shift of an existing CentOS 7 estate into Azure as a migration staging step
- Reproducing and testing against a CentOS 7 environment for compatibility work
For any workload that must stay secure long term, migrate to AlmaLinux, Rocky Linux, CentOS Stream or a current RHEL: CentOS 7 receives no further upstream security updates.
Troubleshooting
Cannot connect via SSH
- Verify the VM is in Running state in the Azure Portal
- Check that port 22 is allowed in the Network Security Group
- Ensure you are using the correct username:
azureuser, or the administrator name you chose - Verify your SSH key matches the one you supplied at create time. Password login is disabled, so a wrong key cannot fall back to a password prompt.
yum reports 404 errors or "Cannot find a valid baseurl"
The image's cached CentOS mirror list points at mirrors that have dropped CentOS 7. Point the repositories at the vault (Step 4), then sudo yum clean all. If you add a third party .repo that references mirror.centos.org or mirrorlist.centos.org, repoint it to https://vault.centos.org/7.9.2009/... as well.
A failed vxagent.service at every boot
systemctl --failed shows vxagent.service failed. It is the start script of an Azure Site Recovery replication agent (package InMageVx) left in the image; its program files are not present, so it fails at boot and does nothing. It does not affect the virtual machine. To stop it being started:
sudo chkconfig vxagent off
sudo systemctl reset-failed vxagent
The same agent adds the dracut module that prints the check_drivers.sh: No such file or directory line when a kernel is installed (Step 5); that message is harmless.
cloud-init status prints a NameError
Run it with sudo: sudo cloud-init status (see Step 7).
Azure agent not running
Check the agent's status:
systemctl status waagent --no-pager
If it is not running, start and enable it with sudo systemctl enable --now waagent.
Security Recommendations
- Do Steps 4 and 5 on every new virtual machine, then plan the migration off CentOS 7.
- Remove the leftover entries from
/root/.ssh/authorized_keysand setPermitRootLogin no(Step 6). - Allow SSH in the Network Security Group from your own address ranges only.
- The image runs with SELinux disabled. If your policy requires SELinux, test your workload with it enabled on a separate virtual machine before you change a running one.
- Enable firewalld if you need a host firewall (Step 8).
Important Notes
CentOS Linux is free and open source. It is not covered by a single licence: it is a distribution assembled from thousands of independently packaged components, each carrying its own terms, including the GPL, LGPL, MIT, BSD, Apache 2.0 and MPL. Every package's terms are readable with rpm -qi <package> and under /usr/share/licenses/. No subscription, licence key or Red Hat entitlement is required.
CentOS Linux 7 reached end of life on 30 June 2024 and receives no further upstream security updates. This image was patched when it was built; Step 5 brings it to the last packages in the CentOS 7.9.2009 vault. Plan a migration to a supported distribution (AlmaLinux, Rocky Linux, CentOS Stream or a current RHEL) for any workload that must remain secure.
CentOS is a trademark of Red Hat, Inc. The name is used here nominatively, only to identify the distribution this image contains. cloudimg is not affiliated with, endorsed by or sponsored by Red Hat.
Support
For assistance with this image, contact cloudimg support:
- Website: www.cloudimg.co.uk
- Product Catalogue: www.cloudimg.co.uk/products
- User Guides: www.cloudimg.co.uk/guides
- SLA: 24 hour response guaranteed