Skip to content

feat(linux): gate custom cloud cert pull on RCV 1P opt-in#7958

Draft
rchincha wants to merge 2 commits intomainfrom
origin/rchinchani/rcv1p
Draft

feat(linux): gate custom cloud cert pull on RCV 1P opt-in#7958
rchincha wants to merge 2 commits intomainfrom
origin/rchinchani/rcv1p

Conversation

@rchincha
Copy link

  • add opt-in check via acms/isOptedInForRootCerts before certificate retrieval

  • use operation-request endpoints for RCV 1P root/intermediate certificate pull

  • keep fallback to legacy cacertificates flow when not opted in

  • harden opt-in detection with curl --fail and JSON boolean match

  • normalize Flatcar cert installation by converting .crt artifacts to .pem during copy

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes #

- add opt-in check via acms/isOptedInForRootCerts before certificate retrieval

- use operation-request endpoints for RCV 1P root/intermediate certificate pull

- keep fallback to legacy cacertificates flow when not opted in

- harden opt-in detection with curl --fail and JSON boolean match

- normalize Flatcar cert installation by converting .crt artifacts to .pem during copy
Copilot AI review requested due to automatic review settings February 26, 2026 01:13
@microsoft-github-policy-service

@rchincha please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"
Contributor License Agreement

Contribution License Agreement

This Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
and conveys certain license rights to Microsoft Corporation and its affiliates (“Microsoft”) for Your
contributions to Microsoft open source projects. This Agreement is effective as of the latest signature
date below.

  1. Definitions.
    “Code” means the computer software code, whether in human-readable or machine-executable form,
    that is delivered by You to Microsoft under this Agreement.
    “Project” means any of the projects owned or managed by Microsoft and offered under a license
    approved by the Open Source Initiative (www.opensource.org).
    “Submit” is the act of uploading, submitting, transmitting, or distributing code or other content to any
    Project, including but not limited to communication on electronic mailing lists, source code control
    systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of
    discussing and improving that Project, but excluding communication that is conspicuously marked or
    otherwise designated in writing by You as “Not a Submission.”
    “Submission” means the Code and any other copyrightable material Submitted by You, including any
    associated comments and documentation.
  2. Your Submission. You must agree to the terms of this Agreement before making a Submission to any
    Project. This Agreement covers any and all Submissions that You, now or in the future (except as
    described in Section 4 below), Submit to any Project.
  3. Originality of Work. You represent that each of Your Submissions is entirely Your original work.
    Should You wish to Submit materials that are not Your original work, You may Submit them separately
    to the Project if You (a) retain all copyright and license information that was in the materials as You
    received them, (b) in the description accompanying Your Submission, include the phrase “Submission
    containing materials of a third party:” followed by the names of the third party and any licenses or other
    restrictions of which You are aware, and (c) follow any other instructions in the Project’s written
    guidelines concerning Submissions.
  4. Your Employer. References to “employer” in this Agreement include Your employer or anyone else
    for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. If Your
    Submission is made in the course of Your work for an employer or Your employer has intellectual
    property rights in Your Submission by contract or applicable law, You must secure permission from Your
    employer to make the Submission before signing this Agreement. In that case, the term “You” in this
    Agreement will refer to You and the employer collectively. If You change employers in the future and
    desire to Submit additional Submissions for the new employer, then You agree to sign a new Agreement
    and secure permission from the new employer before Submitting those Submissions.
  5. Licenses.
  • Copyright License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license in the
    Submission to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute
    the Submission and such derivative works, and to sublicense any or all of the foregoing rights to third
    parties.
  • Patent License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license under
    Your patent claims that are necessarily infringed by the Submission or the combination of the
    Submission with the Project to which it was Submitted to make, have made, use, offer to sell, sell and
    import or otherwise dispose of the Submission alone or with the Project.
  • Other Rights Reserved. Each party reserves all rights not expressly granted in this Agreement.
    No additional licenses or rights whatsoever (including, without limitation, any implied licenses) are
    granted by implication, exhaustion, estoppel or otherwise.
  1. Representations and Warranties. You represent that You are legally entitled to grant the above
    licenses. You represent that each of Your Submissions is entirely Your original work (except as You may
    have disclosed under Section 3). You represent that You have secured permission from Your employer to
    make the Submission in cases where Your Submission is made in the course of Your work for Your
    employer or Your employer has intellectual property rights in Your Submission by contract or applicable
    law. If You are signing this Agreement on behalf of Your employer, You represent and warrant that You
    have the necessary authority to bind the listed employer to the obligations contained in this Agreement.
    You are not expected to provide support for Your Submission, unless You choose to do so. UNLESS
    REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, AND EXCEPT FOR THE WARRANTIES
    EXPRESSLY STATED IN SECTIONS 3, 4, AND 6, THE SUBMISSION PROVIDED UNDER THIS AGREEMENT IS
    PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
    NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
  2. Notice to Microsoft. You agree to notify Microsoft in writing of any facts or circumstances of which
    You later become aware that would make Your representations in this Agreement inaccurate in any
    respect.
  3. Information about Submissions. You agree that contributions to Projects and information about
    contributions may be maintained indefinitely and disclosed publicly, including Your name and other
    information that You submit with Your Submission.
  4. Governing Law/Jurisdiction. This Agreement is governed by the laws of the State of Washington, and
    the parties consent to exclusive jurisdiction and venue in the federal courts sitting in King County,
    Washington, unless no federal subject matter jurisdiction exists, in which case the parties consent to
    exclusive jurisdiction and venue in the Superior Court of King County, Washington. The parties waive all
    defenses of lack of personal jurisdiction and forum non-conveniens.
  5. Entire Agreement/Assignment. This Agreement is the entire agreement between the parties, and
    supersedes any and all prior agreements, understandings or communications, written or oral, between
    the parties relating to the subject matter hereof. This Agreement may be assigned by Microsoft.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces RCV 1P (Root Certificate Validation 1st Party) opt-in gating for custom cloud certificate retrieval in AKS. The change modifies the init-aks-custom-cloud.sh script to check whether a VM is opted into RCV 1P via a new wireserver endpoint (/acms/isOptedInForRootCerts). When opted in, the script uses new operation-request endpoints to pull root and intermediate certificates; otherwise, it falls back to the legacy cacertificates flow.

Changes:

  • Added RCV 1P opt-in detection via wireserver endpoint with JSON boolean matching
  • Implemented new certificate retrieval path using operationrequestsroot and operationrequestsintermediate endpoints
  • Preserved backward compatibility with legacy certificate retrieval for non-opted-in VMs
  • Normalized Flatcar certificate installation by converting .crt files to .pem during copy operation

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")
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function make_request_with_retry is called but never defined in this script. This function is required for the RCV 1P opt-in path to work. Based on similar scripts like init-aks-custom-cloud-operation-requests.sh, this function should be defined before it's used. The function should implement retry logic with exponential backoff for rate limiting and network failures.

Copilot uses AI. Check for mistakes.
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")
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable WIRESERVER_ENDPOINT is used but never defined in this script. This will cause the script to fail when the RCV 1P opt-in path is taken. Based on similar scripts like init-aks-custom-cloud-operation-requests.sh, this should be defined as WIRESERVER_ENDPOINT="http://168.63.129.16" near the top of the script, before the function definitions.

Copilot uses AI. Check for mistakes.

# Extract ResourceFileName values from the JSON response
local cert_filenames
mapfile -t cert_filenames < <(echo "$operation_response" | grep -oP '(?<="ResouceFileName": ")[^"]*')
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON field name is misspelled as "ResouceFileName" (missing 'r' in Resource). This should be "ResourceFileName". This typo will cause the certificate extraction to fail if the wireserver API returns the correctly spelled field name. Verify the actual field name from the wireserver API response and correct the spelling to match.

Suggested change
mapfile -t cert_filenames < <(echo "$operation_response" | grep -oP '(?<="ResouceFileName": ")[^"]*')
mapfile -t cert_filenames < <(echo "$operation_response" | grep -oP '(?<="ResourceFileName": ")[^"]*')

Copilot uses AI. Check for mistakes.
Comment on lines +80 to +82
# Save the certificate to the appropriate location
echo "$cert_content" > "/root/AzureCACertificates/$cert_filename"
echo "Successfully saved certificate: $cert_filename"
Copy link

Copilot AI Feb 26, 2026

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.

Suggested change
# 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 uses AI. Check for mistakes.
Comment on lines +119 to +120
certNames=($(echo $certs | grep -oP '(?<=Name\": \")[^\"]*'))
certBodies=($(echo $certs | grep -oP '(?<=CertBody\": \")[^\"]*'))
Copy link

Copilot AI Feb 26, 2026

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 uses AI. Check for mistakes.
Comment on lines +101 to +104
if optInCheck=$(curl -sS --fail "http://168.63.129.16/acms/isOptedInForRootCerts"); then
:
else
echo "Warning: failed to query root cert opt-in status; defaulting to non-opt-in flow"
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The opt-in check uses curl with --fail flag which will cause curl to fail silently (exit code 22) on HTTP errors, but the captured output in optInCheck might still contain error HTML or be empty. While the grep check on line 107 will handle this gracefully by falling back to the legacy flow, it would be better to add explicit error handling or use -f (fail) with better error checking to ensure robust behavior across all failure scenarios.

Suggested change
if optInCheck=$(curl -sS --fail "http://168.63.129.16/acms/isOptedInForRootCerts"); then
:
else
echo "Warning: failed to query root cert opt-in status; defaulting to non-opt-in flow"
optInCurlStatus=0
optInCheck=$(curl -sS --fail "http://168.63.129.16/acms/isOptedInForRootCerts" 2>/dev/null) || optInCurlStatus=$?
if [ "$optInCurlStatus" -ne 0 ]; then
echo "Warning: failed to query root cert opt-in status (curl exit code $optInCurlStatus); defaulting to non-opt-in flow"
optInCheck=""

Copilot uses AI. Check for mistakes.
else
echo "Not opted in for root certs, skipping CA cert pull and install"
# 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")
Copy link

Copilot AI Feb 26, 2026

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 uses AI. Check for mistakes.
Comment on lines +122 to +133
if [ "$IS_FLATCAR" -eq 1 ]; then
ext=".pem"
fi
for i in ${!certBodies[@]}; do
echo ${certBodies[$i]} | sed 's/\\r\\n/\n/g' | sed 's/\\//g' > "/root/AzureCACertificates/$(echo ${certNames[$i]} | sed "s/.cer/.${ext}/g")"
done
echo "successfully pulled in default certs"
fi
for i in ${!certBodies[@]}; do
echo ${certBodies[$i]} | sed 's/\\r\\n/\n/g' | sed 's/\\//g' > "/root/AzureCACertificates/$(echo ${certNames[$i]} | sed "s/.cer/.${ext}/g")"
done

IFS=$IFS_backup

if [ "$IS_FLATCAR" -eq 0 ]; then
if [ "${IS_FLATCAR}" -eq 0 ]; then
Copy link

Copilot AI Feb 26, 2026

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 uses AI. Check for mistakes.
- add a dedicated CARefresh parameter set with -CARefreshOnly mode for certificate-only execution
- implement RCV 1P cert retrieval from WireServer, including opt-in detection via isOptedInForRootCerts
- add operation-request certificate download path (operationrequestsroot/operationrequestsintermediate)
- keep backward-compatible fallback to legacy cacertificates endpoint when VM is not opted in
- add retry/backoff wrapper for WireServer calls and structured RCV1P logging helper
- install downloaded certs into LocalMachine certificate stores (Root for self-signed, CA for intermediates)
- register a daily SYSTEM scheduled task (aks-rcv1p-cert-refresh) to rerun cert refresh via this script
- wire AKS custom cloud base-prep flow to run RCV 1P refresh and task registration
- document RCV 1P intent with inline comment block for maintainability
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants