Skip to content

Instantly share code, notes, and snippets.

@mavaddat
Last active April 25, 2024 08:56
Show Gist options
  • Save mavaddat/29bea8cbc54d14b5ca04aef6af0cfeca to your computer and use it in GitHub Desktop.
Save mavaddat/29bea8cbc54d14b5ca04aef6af0cfeca to your computer and use it in GitHub Desktop.
Setting Python REQUESTS_CA_BUNDLE for Windows using all the available certificates on the machine. Answer to this Stackoverflow question: https://stackoverflow.com/questions/51925384/unable-to-get-local-issuer-certificate-when-using-requests-in-python
#Requires -Version 6.0
# Allocate a temporary directory for receiving the certificates
$tmpCertsDir = New-Item -Path "$env:TEMP" -Name "Certs$(Get-Date -Format FileDateTimeUniversal)" -ItemType Directory -Force
# Collect the certs from the local machine
$certs = Get-ChildItem -Path Cert:\ -Recurse | Where-Object -FilterScript { $_.Thumbprint }
# This will contain the paths to the resulting PEM files
$pemPaths = [string[]]::new($certs.Count)
$certs | ForEach-Object -Process {
$curCert = $_.FriendlyName
$i = $certs.IndexOf($_)
if ([string]::IsNullOrEmpty($curCert)) {
$curCert = $_.Subject
}
if ([string]::IsNullOrEmpty($curCert)) {
$curCert = $_.Thumbprint
}
Write-Progress -Activity 'Copying certificates' -Status "Copying $curCert" -PercentComplete (100 * $i / $certs.Count)
$outCert = Join-Path -Path $tmpCertsDir -ChildPath "$($_.Thumbprint).crt"
$pemPaths[$i] = Join-Path -Path $export.Directory.FullName -ChildPath "$($export.BaseName).pem"
if (-not (Test-Path -Path $outCert -PathType Leaf)) {
$export = $_ | Export-Certificate -Type CERT -FilePath $outCert -Force
openssl x509 -inform DER -in $export.FullName -out ($pemPaths[$i]) -text
}
} -End {
Remove-Item -Path $tmpCertsDir\*.crt -Force
Write-Progress -Activity 'Copying certificates' -Status 'Done' -Completed
}
<# if you already have certifi installed, you can use
$RequestsCaBundle = python -c 'import certifi; print(certifi.where())' # "$Env:LOCALAPPDATA\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\certifi\cacert.pem"
#>
<# Apparently, we aren't allowed to write into the site-packages directory, so this does not work
$RequestsCaBundle = Join-Path -Path (python -c "import sys; [print(p) for p in sys.path if p.endswith(r'Lib\site-packages')]" | Sort-Object -Unique) -ChildPath "cacerts.pem"
#>
$RequestsCaBundle = "$env:USERPROFILE\cacerts.pem" # Not sure if this is the best location for cacerts on Windows
$rcaTmp = New-TemporaryFile
for ($i = 0; $i -lt $pemPaths.Count; $i++) {
Write-Progress -Activity 'Concatenating certificates' -Status "Concatenating $curCert" -PercentComplete (100 * $i / $pemPaths.Count)
$pemPaths[$i] | Get-Content | Add-Content -Path $rcaTmp -Force
}
Remove-Item -Path $tmpCertsDir -Recurse -Force
try {
Move-Item -Path $rcaTmp -Destination $RequestsCaBundle -Force -ErrorAction Stop
}
catch [System.UnauthorizedAccessException] {
if (-not(Test-Path -Path $RequestsCaBundle -PathType Leaf) -and $rcaTmp.Length -gt 0) {
$errOut = New-TemporaryFile
# Move $rcaTmp to $RequestsCaBundle using RunAs verb
Start-Process -FilePath pwsh -ArgumentList @('NonInteractive', 'NoProfile', 'NoLogo', "-Command `"try { Move-Item -Path '$rcaTmp' -Destination '$RequestsCaBundle' -Force *>&1 }catch{`$_} ) | Export-Clixml -Path $errOut -Force`"") -Verb RunAs
if ($errOut.Length -gt 0) {
Import-Clixml -Path $errOut | Write-Error
}
Remove-Item -Path $errOut
}
}
if (Test-Path -Path $RequestsCaBundle -PathType Leaf) {
$env:REQUESTS_CA_BUNDLE = "$RequestsCaBundle"
try {
[System.Environment]::SetEnvironmentVariable('REQUESTS_CA_BUNDLE',$RequestsCaBundle,[System.EnvironmentVariableTarget]::Machine)
}
catch [System.Management.Automation.MethodInvocationException] {
$errOut = New-TemporaryFile
# Set the REQUESTS_CA_BUNDLE environment variable at the machine scope using RunAs verb
Start-Process -FilePath pwsh -ArgumentList @('NonInteractive', 'NoProfile', 'NoLogo', "-Command `"try { [System.Environment]::SetEnvironmentVariable('REQUESTS_CA_BUNDLE',$RequestsCaBundle,[System.EnvironmentVariableTarget]::Machine) *>&1 }catch{`$_} ) | Export-Clixml -Path $errOut -Force`"") -Verb RunAs
if ($errOut.Length -gt 0) {
Import-Clixml -Path $errOut | Write-Error
}
Remove-Item -Path $errOut
}
}
else {
Write-Warning "Unable to write to '$RequestsCaBundle'; Check permissions and try again."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment