Every request took four hops
The server has no direct internet. All traffic goes through one corporate proxy, and the IP in the error message is that proxy, not Red Hat. The first question was which hop was saying no.
Seven explanations, one survivor
Each card is a cause we considered. Select one to highlight the moments in the log that tested it.
How the call went
Times are from the Riyadh desktop clock in each photo. Nobody on our side could touch the server; every command was typed by the client and sent back as a phone photo of the screen.
-
Reading the error
dnf had a proxy set in
/etc/dnf/dnf.conf, and no proxy variables in the shell. The 403 named the proxy's IP and was only 465 bytes. The proxy was clearly reachable. Something past it was saying no.# grep -i proxy /etc/dnf/dnf.conf proxy=http://10.10.160.90:8080/ # dnf --setopt=proxy=http://10.10.160.90:8080 update 'php*' - Status code: 403 for https://cdn.redhat.com/.../repomd.xml (IP: 10.10.160.90)
Hypothesis. The proxy decrypts HTTPS and strips the client certificate Red Hat needs. Common on government networks. This turned out to be wrong.
-
Is the server registered?
# subscription-manager status Overall Status: Disabled Content Access Mode is set to Simple Content Access. # subscription-manager identity system identity: cc17f676-ad58-48bb-a901-907d93d72b59 org ID: 19357488
Ruled out. "Disabled" looks alarming but is the normal status line under Simple Content Access. The server is registered.
-
Other repos work through the same proxy
# subscription-manager config --list | egrep 'proxy_hostname|proxy_port' proxy_hostname = 10.10.160.90 proxy_port = 8080 # dnf upgrade --refresh "php*" GetPageSpeed packages for Enterprise Linux 9 219 kB/s | 702 kB Extra Packages for Enterprise Linux 7 76 kB/s | 17 MB Red Hat Enterprise Linux 9 - BaseOS 403 on every file
Narrowed. General HTTPS through the proxy works. Only the one site that requires a client certificate fails. Side finding: an EPEL 7 repo was configured on a RHEL 9 box.
-
The decisive curl
We sent the same request with the server's entitlement certificate and Red Hat's CA, and read the TLS handshake.
# curl -v -x http://10.10.160.90:8080 --cert "$C" --key "$E" \ --cacert /etc/rhsm/ca/redhat-uep.pem https://cdn.redhat.com/.../repomd.xml > CONNECT cdn.redhat.com:443 HTTP/1.1 < HTTP/1.1 200 Connection established * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * issuer: O=Red Hat, Inc.; CN=Red Hat Entitlement Operations Authority * SSL certificate verify ok. < HTTP/1.1 403 Forbidden <TITLE>Access Denied</TITLE>
Turning point. The proxy only opened a tunnel. Inside it, the server spoke directly to Red Hat with a valid certificate. The refusal came from Red Hat's side. The SSL-inspection theory was dropped.
-
Trying to go around it
# dnf upgrade 'php*' --disablerepo='rhel-9-*' Dependencies resolved. Nothing to do.Dead end. Later
rpm -qashowed why: every PHP package was8.2.30-1.module+el9.7, from Red Hat AppStream. Its updates could only come from the blocked CDN. -
The clock
# date Thu Oct 22 09:38:42 AM EDT 2026Ruled out. 09:38 EDT is 13:38 UTC, which is 16:38 in Riyadh, matching the desktop clock.
Slip: four commands were pasted as one line. Their line breaks were lost, so everything after the first
grepbecame its arguments. From here on, one command per paste. -
Reading the certificate
# rct cat-cert /etc/pki/entitlement/6054126864648727161.pem | grep -Ei 'start date|end date|...' Start Date: 2026-08-08 10:18:45+00:00 End Date: 2027-08-08 10:18:45+00:00 Name: Content Access
Valid dates.
list --consumedsaid "No consumed subscription pools", which is also expected under Simple Content Access.Slip: the first version of this grep included
type:, which matched every repo in the certificate and flooded the screen withType: yum. -
Does the certificate cover BaseOS?
# rct cat-cert ...pem | grep -F -e '/content/dist/rhel9/$releasever/x86_64/baseos/os' \ -e '/content/dist/rhel9/$releasever/x86_64/appstream/os' URL: /content/dist/rhel9/$releasever/x86_64/appstream/os URL: /content/dist/rhel9/$releasever/x86_64/baseos/os
Ruled out. The certificate allows exactly what dnf asks for. Every check on the client's side now passed.
-
Akamai's reference number
# curl --proxy 10.10.160.90:8080 https://cdn.redhat.com/.../repomd.xml curl: (60) SSL certificate problem: self-signed certificate in certificate chain # curl --proxy 10.10.160.90:8080 https://cdn.redhat.com/.../repomd.xml -k <H1>Access Denied</H1> Reference #18.ecc11302.1792680174.3bbb612c https://errors.edgesuite.net/18.ecc11302.1792680174.3bbb612c
Red Hat side. The "self-signed" error is normal: cdn.redhat.com uses Red Hat's private CA, which is not in the system store. The Access Denied page is served by Akamai, the CDN in front of Red Hat. The reference number is what Red Hat support can trace.
-
Plan B: PHP from a public repo
The team drafted an EPEL 9 + Remi switch to the
php:remi-8.2stream. The review added two corrections: put--disablerepo='rhel-*'on every dnf line, not just the upgrade, because dnf aborts on the 403 otherwise; and remove the stray EPEL 7 repo first.Exposure. A Notepad window on the shared, recorded screen showed a password in plain text. It should be rotated.
-
A colleague updated PHP another way
Using dnf against a different package source, so the update no longer depended on the Red Hat CDN. Which source exactly is still to be confirmed with
dnf list installed 'php*'andrpm -qi php-cli.
PHP is updated. The 403 is not fixed.
Verified fine
- Proxy tunnels cdn.redhat.com without inspecting it
- dnf and rhsm both point at 10.10.160.90:8080
- Registered to org 19357488, Simple Content Access
- Server clock correct
- Entitlement certificate valid and covers BaseOS and AppStream
Still open
- Red Hat case: org 19357488, system
cc17f676-…d72b59, the 403 URL, Akamai reference, and the proxy's public IP fromcurl -x http://10.10.160.90:8080 https://ifconfig.me - Check console.redhat.com for an active RHEL subscription or an account hold
- Kernel, OpenSSL and the rest of the OS still get no updates
- Replace the EPEL 7 repo with EPEL 9
- Rotate the password shown on screen
- Record which source the PHP update came from
What to do first next time
Run the verbose curl with the entitlement cert first. One command shows the proxy's CONNECT reply, the TLS issuer and the CDN's answer. It would have split proxy from Red Hat in minutes.
Under Simple Content Access, "Disabled" and "no consumed pools" are normal. A valid certificate proves registration, not that the account may download.
Find where the package came from before planning the update.
rpm -qa 'php*'showingmodule+el9meant the fix lived behind the blocked CDN.Over photos and remote desktops, send one command per paste and avoid greps that can match hundreds of lines.
Keep secrets off a shared screen. Close Notepad and password managers before sharing.