Skip to content

Commit dce1bd5

Browse files
NSSPKrishnaNSSPKrishna
andauthored
feat: Windows user least privilege v2 (#1343)
Co-authored-by: NSSPKrishna <pnialdhuri@newrelic.com>
1 parent cb998ca commit dce1bd5

1 file changed

Lines changed: 161 additions & 64 deletions

File tree

recipes/newrelic/infrastructure/windows.yml

Lines changed: 161 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ install:
4242
- task: assert_required_permissions
4343
- task: assert_required_powershell
4444
- task: collect_meta
45-
- task: remove_any_previous
4645
- task: download_infra
46+
- task: remove_if_old_version
47+
- task: stop_existing_service
4748
- task: install_infra
4849
- task: start_infra
4950
- task: assert_agent_status_ok
@@ -77,64 +78,108 @@ install:
7778
}
7879
'
7980
80-
remove_any_previous:
81+
remove_if_old_version:
8182
ignore_error: true
8283
cmds:
8384
- |
8485
powershell -command '
85-
try{
86-
if ( Get-Service "newrelic-infra" -ErrorAction SilentlyContinue) {
87-
Stop-Service -Name "newrelic-infra" -Force -PassThru | Out-Null
86+
$minVersion = [Version]"1.73.0"
87+
$AGENT_VERSION = "{{.INFRASTRUCTURE_AGENT_INSTALLER_VERSION}}"
88+
89+
# Check if the target version being installed is < 1.73.0
90+
if ($AGENT_VERSION) {
91+
try {
92+
$target = [Version]$AGENT_VERSION
93+
if ($target -ge $minVersion) {
94+
exit 0
95+
}
96+
} catch {
97+
# Could not parse target version, fall through to installed version check
8898
}
89-
function Find-UninstallGuids {
90-
param (
91-
[Parameter(Mandatory)]
92-
[string]$Match
93-
)
94-
95-
$baseKeys = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall `
96-
| % { $_.Name.TrimStart("HKEY_LOCAL_MACHINE\") }
97-
98-
$wowKeys = Get-ChildItem -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall `
99-
| % { $_.Name.TrimStart("HKEY_LOCAL_MACHINE\") }
100-
101-
$allKeys = $baseKeys + $wowKeys
102-
103-
$uninstallIds = New-Object System.Collections.ArrayList
104-
foreach ($key in $allKeys) {
105-
$keyData = Get-Item -LiteralPath "HKLM:\$key" -ErrorAction SilentlyContinue
106-
if ($keyData) {
107-
$name = $keyData.GetValue("DisplayName")
108-
if ($name -and $name -match $Match) {
109-
$keyId = Split-Path $key -Leaf
110-
$uninstallIds.Add($keyId) | Out-Null
111-
}
99+
}
100+
101+
$baseKeys = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -ErrorAction SilentlyContinue `
102+
| % { $_.Name.TrimStart("HKEY_LOCAL_MACHINE\") }
103+
$wowKeys = Get-ChildItem -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall -ErrorAction SilentlyContinue `
104+
| % { $_.Name.TrimStart("HKEY_LOCAL_MACHINE\") }
105+
$allKeys = $baseKeys + $wowKeys
106+
107+
# If no specific target version, check the currently installed version
108+
if (-not $AGENT_VERSION) {
109+
$installedVersion = $null
110+
foreach ($key in $allKeys) {
111+
$keyData = Get-Item -LiteralPath "HKLM:\$key" -ErrorAction SilentlyContinue
112+
if ($keyData) {
113+
$name = $keyData.GetValue("DisplayName")
114+
if ($name -and $name -match "New Relic Infrastructure Agent") {
115+
$installedVersion = $keyData.GetValue("DisplayVersion")
116+
break
112117
}
113118
}
119+
}
114120
115-
if ($uninstallIds.Count -eq 0) {
116-
return @()
117-
}
121+
if (-not $installedVersion) {
122+
exit 0
123+
}
118124
119-
return $uninstallIds
125+
try {
126+
$current = [Version]$installedVersion
127+
} catch {
128+
exit 0
129+
}
130+
131+
if ($current -ge $minVersion) {
132+
exit 0
133+
}
134+
}
135+
136+
try {
137+
if (Get-Service "newrelic-infra" -ErrorAction SilentlyContinue) {
138+
Stop-Service -Name "newrelic-infra" -Force -PassThru | Out-Null
139+
}
140+
141+
$uninstallIds = New-Object System.Collections.ArrayList
142+
foreach ($key in $allKeys) {
143+
$keyData = Get-Item -LiteralPath "HKLM:\$key" -ErrorAction SilentlyContinue
144+
if ($keyData) {
145+
$name = $keyData.GetValue("DisplayName")
146+
if ($name -and $name -match "New Relic Infrastructure Agent") {
147+
$keyId = Split-Path $key -Leaf
148+
$uninstallIds.Add($keyId) | Out-Null
149+
}
150+
}
120151
}
121152
122-
$uninstallIds = Find-UninstallGuids -Match "New Relic Infrastructure Agent"
123153
foreach ($uninstallId in $uninstallIds) {
124154
$uninstallCommand = "msiexec /x """ + $uninstallId + """ /qn"
125155
$er = (Invoke-Expression $uninstallCommand) 2>&1
126-
if($er.Exception){
156+
if ($er.Exception) {
127157
throw $er.Exception
128158
}
129-
# wait here to allow uninstall command to complete since it returns without waiting
130159
Start-Sleep -s 15
131160
}
132-
}
133-
catch {
161+
} catch {
134162
throw $_.Exception
135163
}
136164
'
137165
166+
stop_existing_service:
167+
cmds:
168+
- |
169+
powershell -command '
170+
$serviceName = "newrelic-infra"
171+
$service = Get-Service $serviceName -ErrorAction SilentlyContinue
172+
if ($service -ne $null) {
173+
if ($service.Status -eq "Running") {
174+
Write-Host "Stopping existing New Relic Infrastructure service before upgrade..."
175+
Stop-Service -Name $serviceName -Force
176+
Start-Sleep -Seconds 2
177+
Write-Host "Service stopped successfully"
178+
}
179+
}
180+
exit 0
181+
'
182+
138183
download_infra:
139184
cmds:
140185
- |
@@ -181,40 +226,80 @@ install:
181226
$LICENSE_KEY = "{{.NEW_RELIC_LICENSE_KEY}}"
182227
$InfraConfig = "C:\\Program Files\\New Relic\\newrelic-infra\\newrelic-infra.yml"
183228
$AGENT_VERSION = "{{.INFRASTRUCTURE_AGENT_INSTALLER_VERSION}}"
229+
$MSI_PATH = "$env:TEMP\newrelic-infra.msi"
230+
$EXTRACT_PATH = "$env:TEMP\\msi_extracted_install"
184231
185232
if ($AGENT_VERSION) {
186233
Write-Host "Installing specific version of New Relic Infrastructure Agent: $AGENT_VERSION"
187234
} else {
188235
Write-Host "Installing latest version of New Relic Infrastructure Agent"
189236
}
190237
191-
if (Test-Path $InfraConfig) {
192-
msiexec.exe /qn /i "$env:TEMP\newrelic-infra.msi" | Out-Null
193-
194-
(Get-Content $InfraConfig) | Where-Object {
195-
$_ -notmatch "^staging"
196-
} | Set-Content $InfraConfig
197-
198-
(Get-Content $InfraConfig) | Where-Object {
199-
$_ -notmatch "^enable_process_metrics"
200-
} | Set-Content $InfraConfig
201-
202-
(Get-Content $InfraConfig) | Where-Object {
203-
$_ -notmatch "^status_server_enabled"
204-
} | Set-Content $InfraConfig
205-
206-
(Get-Content $InfraConfig) | Where-Object {
207-
$_ -notmatch "^status_server_port"
208-
} | Set-Content $InfraConfig
209-
210-
(Get-Content $InfraConfig) | Foreach-Object {
211-
$_ -replace "^license_key: .*", ("license_key: " + $LICENSE_KEY) `
212-
} | Set-Content $InfraConfig
213-
214-
(Get-Content -raw $InfraConfig) -replace "(?m)^custom_attributes:(?s:.*?)(^\s.+:.+\n)+", "" | Set-Content $InfraConfig
215-
238+
# Check if service already exists to determine installation method
239+
$existingService = Get-Service -Name "newrelic-infra" -ErrorAction SilentlyContinue
240+
241+
if ($existingService) {
242+
Write-Host "Existing service detected."
243+
244+
# Extract MSI to temp folder
245+
Write-Host "Extracting MSI to $EXTRACT_PATH..."
246+
if (Test-Path $EXTRACT_PATH) {
247+
Remove-Item -Path $EXTRACT_PATH -Recurse -Force -ErrorAction SilentlyContinue
248+
}
249+
New-Item -Path $EXTRACT_PATH -ItemType Directory -Force | Out-Null
250+
251+
# Extract using msiexec /a (administrative install - extracts files)
252+
$extractProcess = Start-Process -FilePath "msiexec.exe" -ArgumentList "/a `"$MSI_PATH`" /qn TARGETDIR=`"$EXTRACT_PATH`" /L*v `"$env:TEMP\\msi_extract.log`"" -Wait -NoNewWindow -PassThru
253+
if ($extractProcess.ExitCode -ne 0) {
254+
Write-Host -ForegroundColor Red "Failed to extract MSI: Exit code $($extractProcess.ExitCode)"
255+
exit $extractProcess.ExitCode
256+
}
257+
Write-Host "MSI extracted successfully"
258+
259+
# Locate the installer.ps1 in extracted files
260+
$installerScript = Get-ChildItem -Path $EXTRACT_PATH -Filter "installer.ps1" -Recurse | Select-Object -First 1
261+
if (-not $installerScript) {
262+
Write-Host -ForegroundColor Red "installer.ps1 not found in extracted MSI"
263+
exit 1
264+
}
265+
Write-Host "Found installer.ps1 at: $($installerScript.FullName)"
266+
267+
# Run installer.ps1 directly from extracted location (triggers ZIP installation path)
268+
Write-Host "Running installer.ps1 ..."
269+
$scriptDir = $installerScript.DirectoryName
270+
Push-Location $scriptDir
271+
272+
try {
273+
& "$($installerScript.FullName)" -LicenseKey $LICENSE_KEY
274+
275+
if ($LASTEXITCODE -ne 0) {
276+
Write-Host -ForegroundColor Red "installer.ps1 failed with exit code: $LASTEXITCODE"
277+
if (Test-Path "C:\\ProgramData\\New Relic\\newrelic-infra\\tmp\\newrelic_installer_debug.log") {
278+
Write-Host "Debug log:" -ForegroundColor Yellow
279+
Get-Content "C:\\ProgramData\\New Relic\\newrelic-infra\\tmp\\newrelic_installer_debug.log" -Tail 20
280+
}
281+
exit $LASTEXITCODE
282+
}
283+
} finally {
284+
Pop-Location
285+
}
286+
287+
Write-Host "installation completed successfully"
216288
} else {
217-
msiexec.exe /qn /i "$env:TEMP\newrelic-infra.msi" GENERATE_CONFIG=true LICENSE_KEY="$LICENSE_KEY" | Out-Null
289+
Write-Host "No existing service detected"
290+
291+
# Fresh install - use MSI directly (faster, standard Windows installation)
292+
$process = Start-Process -FilePath "msiexec.exe" -ArgumentList "/qn /i `"$MSI_PATH`" GENERATE_CONFIG=true LICENSE_KEY=`"$LICENSE_KEY`" /L*v `"$env:TEMP\\msi_install.log`"" -Wait -NoNewWindow -PassThru
293+
if ($process.ExitCode -ne 0) {
294+
Write-Host -ForegroundColor Red "MSI installation failed with exit code: $($process.ExitCode)"
295+
if (Test-Path "C:\\ProgramData\\New Relic\\newrelic-infra\\tmp\\newrelic_installer_debug.log") {
296+
Write-Host "Debug log:" -ForegroundColor Yellow
297+
Get-Content "C:\\ProgramData\\New Relic\\newrelic-infra\\tmp\\newrelic_installer_debug.log" -Tail 20
298+
}
299+
exit $process.ExitCode
300+
}
301+
302+
Write-Host "Installation completed successfully"
218303
}
219304
220305
$NEW_RELIC_REGION = "{{.NEW_RELIC_REGION}}"
@@ -237,6 +322,18 @@ install:
237322
"@
238323
239324
Add-Content -Path $InfraConfig -Value $customAttributes -Force -Encoding utf8
325+
326+
# Restart service only for fresh installs to pick up config changes
327+
# For upgrades, installer.ps1 already handles the restart
328+
if (-not $existingService) {
329+
$service = Get-Service -Name "newrelic-infra" -ErrorAction SilentlyContinue
330+
if ($service -and $service.Status -eq "Running") {
331+
Write-Host "Restarting service to apply configuration changes..."
332+
Restart-Service -Name "newrelic-infra" -Force
333+
Start-Sleep -Seconds 3
334+
Write-Host "Service restarted with updated configuration"
335+
}
336+
}
240337
'
241338
242339
start_infra:
@@ -359,4 +456,4 @@ postInstall:
359456
Edit these files to make changes or configure advanced features for the agent. See the docs for options:
360457
Infrastructure Agent: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings
361458
362-
Note: Process monitoring has been enabled by default - all other config options are left to the user.
459+
Note: Process monitoring has been enabled by default - all other config options are left to the user.

0 commit comments

Comments
 (0)