-
Notifications
You must be signed in to change notification settings - Fork 250
feat(linux): gate custom cloud cert pull on RCV 1P opt-in #7958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4e12b58
2277404
31145fe
9ede6e0
0b5c767
172daf9
aa14963
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,29 +24,159 @@ fi | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "distribution is $distribution" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Running on $NAME" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # The purpose of RCV 1P is to reliably distribute root and intermediate certificates at scale to | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # only Microsoft 1st party (1P) virtual machines (VM) and virtual machine scale sets (VMSS). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # This is critical for initiatives such as Microsoft PKI. RCV 1P ensures that these certificates | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # are installed on the node at creation time. This eliminates the need for your VM to be connected | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # to the internet and ping an endpoint to receive certificate packages. The feature also eliminates | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # the dependency on updates to AzSecPack to receive the latest root and intermediate certs. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # RCV 1P is designed to work completely autonomously from the user perspective on all Azure 1st | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # party VMs. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Below code calls the wireserver to get the list of CA certs for this cloud and saves them to /root/AzureCACertificates. Then it copies them to the appropriate location based on distro and updates the CA bundle. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # http://168.63.129.16 is a constant for the host's wireserver endpoint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| certs=$(curl "http://168.63.129.16/machine?comp=acmspackage&type=cacertificates&ext=json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WIRESERVER_ENDPOINT="http://168.63.129.16" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Function to make HTTP request with retry logic for rate limiting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| make_request_with_retry() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local url="$1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local max_retries=10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local retry_delay=3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local attempt=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local response | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while [ $attempt -le $max_retries ]; do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| response=$(curl -f --no-progress-meter "$url") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local request_status=$? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if echo "$response" | grep -q "RequestRateLimitExceeded"; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sleep $retry_delay | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retry_delay=$((retry_delay * 2)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attempt=$((attempt + 1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif [ $request_status -ne 0 ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sleep $retry_delay | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attempt=$((attempt + 1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "$response" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "exhausted all retries, last response: $response" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Function to process certificate operations from a given endpoint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process_cert_operations() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local endpoint_type="$1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local operation_response | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Retrieving certificate operations for type: $endpoint_type" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| operation_response=$(make_request_with_retry "${WIRESERVER_ENDPOINT}/machine?comp=acmspackage&type=$endpoint_type&ext=json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rchincha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local request_status=$? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rchincha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -z "$operation_response" ] || [ $request_status -ne 0 ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Warning: No response received or request failed for: ${WIRESERVER_ENDPOINT}/machine?comp=acmspackage&type=$endpoint_type&ext=json" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Extract ResourceFileName values from the JSON response | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local cert_filenames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mapfile -t cert_filenames < <(echo "$operation_response" | grep -oP '(?<="ResouceFileName": ")[^"]*') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rchincha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mapfile -t cert_filenames < <(echo "$operation_response" | grep -oP '(?<="ResouceFileName": ")[^"]*') | |
| mapfile -t cert_filenames < <(echo "$operation_response" | grep -oP '(?<="ResouceFileName":\s*")[^"]*|(?<="ResourceFileName":\s*")[^"]*') |
Copilot
AI
Feb 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the RCV 1P opt-in path is taken, certificates are saved with their original filenames (including .crt extension) in line 81. However, the Flatcar cert installation logic at lines 143-147 attempts to copy files matching "*.crt" pattern. This creates an inconsistency: the fallback path (lines 121-124) saves files with .pem extension for Flatcar, but the RCV 1P path saves them as .crt regardless of distro. Either the cert saving logic should respect IS_FLATCAR and save as .pem, or the RCV 1P cert download should ensure filenames use appropriate extensions for each distro.
| # Save the certificate to the appropriate location | |
| echo "$cert_content" > "/root/AzureCACertificates/$cert_filename" | |
| echo "Successfully saved certificate: $cert_filename" | |
| # Determine target filename based on distro to match cert installation expectations | |
| local target_cert_filename="$cert_filename" | |
| if [ "$IS_FLATCAR" -eq 1 ]; then | |
| # For Flatcar, use .pem extension to align with fallback cert handling | |
| target_cert_filename="${filename}.pem" | |
| fi | |
| # Save the certificate to the appropriate location | |
| echo "$cert_content" > "/root/AzureCACertificates/$target_cert_filename" | |
| echo "Successfully saved certificate: $target_cert_filename" |
Copilot
AI
Mar 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the opted-in (operation-requests) path, cert filenames are saved exactly as returned (e.g., .cer/.crt/.pem), but the install step later only copies /root/AzureCACertificates/*.crt. If WireServer returns .cer (as the legacy flow suggests), no files will match and no certs will be installed. Normalize the saved filenames/extensions (e.g., always write .crt on Ubuntu/Mariner and handle Flatcar separately) or broaden the install glob to include the actual extensions returned.
| # Save the certificate to the appropriate location | |
| echo "$cert_content" > "/root/AzureCACertificates/$cert_filename" | |
| echo "Successfully saved certificate: $cert_filename" | |
| # Determine the filename to use when saving the certificate. | |
| # On non-Flatcar systems, normalize to a .crt extension so that later | |
| # install steps that use /root/AzureCACertificates/*.crt will pick it up. | |
| local save_filename | |
| if [ "$IS_FLATCAR" -eq 1 ]; then | |
| save_filename="$cert_filename" | |
| else | |
| save_filename="${filename}.crt" | |
| fi | |
| # Save the certificate to the appropriate location | |
| echo "$cert_content" > "/root/AzureCACertificates/$save_filename" | |
| echo "Successfully saved certificate: $save_filename (original: $cert_filename)" |
Copilot
AI
Feb 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fallback curl request to retrieve certificates lacks error handling. Unlike the RCV 1P path which uses make_request_with_retry with retry logic, this curl command has no --fail flag, no retry mechanism, and no validation of the response. If the wireserver is temporarily unavailable or rate-limits the request, the script will continue with potentially empty or malformed data, leading to provisioning failures. Consider adding retry logic and error checking similar to the RCV 1P path.
Copilot
AI
Feb 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable expansions should be quoted to prevent word splitting and glob expansion. The expressions ${certBodies[@]} and ${certNames[@]} within command substitutions should have proper quoting. The use of unquoted variables in command substitution, especially with grep and sed, can lead to unexpected behavior if the data contains special characters or spaces.
Copilot
AI
Feb 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The quote style change from "$IS_FLATCAR" to "${IS_FLATCAR}" is good for consistency, but the original comparison at line 122 still uses the old style "$IS_FLATCAR". For consistency, all IS_FLATCAR comparisons in the script should use the same quote style.
Copilot
AI
Mar 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flatcar branch now loops over /root/AzureCACertificates/*.crt, but in the non-opt-in (legacy) path this script writes certs with a .pem extension (see ext=".pem"). When not opted in, this glob won't match and the copy will fail, leaving Flatcar without installed custom cloud certs. Either keep copying .pem for the legacy flow or normalize the downloaded artifacts to .crt consistently before the copy step (and enable nullglob to avoid iterating on a literal pattern).
Copilot
AI
Mar 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flatcar install loop iterates over /root/AzureCACertificates/*.crt, but the non-opted-in flow writes .pem files (and the opted-in flow may write .cer). This loop will no-op (and then run update-ca-certificates) if no .crt files exist. Align the Flatcar copy/convert logic with the actual extensions produced by both flows (e.g., convert whatever was downloaded into .pem during the copy step, or standardize downloads to .crt).
Uh oh!
There was an error while loading. Please reload this page.