Skip to content

Commit 2ce3ab2

Browse files
Merge pull request #159 from steviecoaster/gh158
(#158) Secure Jenkins installation with an SSL Certificate
2 parents 030f034 + 6db96df commit 2ce3ab2

File tree

8 files changed

+594
-311
lines changed

8 files changed

+594
-311
lines changed

README.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,26 @@ Below are the minimum requirements for setting up your C4B server via this guide
140140
> </ul>
141141
> </details>
142142
143-
### Step 4: SSL Setup
143+
### Step 4: Jenkins Setup
144+
145+
1. In the same **elevated** PowerShell console as above, paste and run the following code:
146+
147+
```powershell
148+
Set-Location "$env:SystemDrive\choco-setup\files"
149+
.\Start-C4bJenkinsSetup.ps1
150+
```
151+
152+
> <details>
153+
> <summary><strong>What does this script do? (click to expand)</strong></summary>
154+
> <ul class="list-style-type-disc">
155+
> <li>Installs Jenkins package</li>
156+
> <li>Updates Jenkins plugins</li>
157+
> <li>Configures pre-downloaded Jenkins scripts for Package Internalizer automation</li>
158+
> <li>Sets up pre-defined Jenkins jobs for the scripts above</li>
159+
> </ul>
160+
> </details>
161+
162+
### Step 5: SSL Setup
144163
145164
1. In the same **elevated** PowerShell console as above, paste and run the following code:
146165
@@ -181,25 +200,6 @@ Below are the minimum requirements for setting up your C4B server via this guide
181200
> <li>Adds SSL certificate configuration for Nexus and CCM web portals</li>
182201
> <li>Generates a `Register-C4bEndpoint.ps1` script for you to easily set up endpoint clients</li>
183202
> <li>Outputs data to a JSON file to pass between scripts</li>
184-
> </ul>
185-
> </details>
186-
187-
### Step 5: Jenkins Setup
188-
189-
1. In the same **elevated** PowerShell console as above, paste and run the following code:
190-
191-
```powershell
192-
Set-Location "$env:SystemDrive\choco-setup\files"
193-
.\Start-C4bJenkinsSetup.ps1
194-
```
195-
196-
> <details>
197-
> <summary><strong>What does this script do? (click to expand)</strong></summary>
198-
> <ul class="list-style-type-disc">
199-
> <li>Installs Jenkins package</li>
200-
> <li>Updates Jenkins plugins</li>
201-
> <li>Configures pre-downloaded Jenkins scripts for Package Internalizer automation</li>
202-
> <li>Sets up pre-defined Jenkins jobs for the scripts above</li>
203203
> <li>Writes a Readme.html file to the Public Desktop with account information for C4B services</li>
204204
> <li>Auto-opens README, CCM, Nexus, and Jenkins in your web browser</li>
205205
> <li>Removes temporary JSON files used during provisioning</li>

Set-SslSecurity.ps1

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,35 @@ certificate is placed in the required local machine store, and then the script
1313
generates SSL bindings for both Nexus and the Central Management website using the
1414
certificate.
1515
#>
16-
[CmdletBinding()]
16+
[CmdletBinding(DefaultParameterSetName='SelfSigned')]
1717
[OutputType([string])]
1818
param(
1919
# The certificate thumbprint that identifies the target SSL certificate in
2020
# the local machine certificate stores.
2121
# Ignored if supplied alongside -Subject.
22-
[Parameter(ValueFromPipeline)]
22+
[Parameter(ValueFromPipeline, ParameterSetName='Thumbprint')]
23+
[ArgumentCompleter({
24+
Get-ChildItem Cert:\LocalMachine\My | ForEach-Object {
25+
[System.Management.Automation.CompletionResult]::new(
26+
$_.Thumbprint,
27+
$_.Thumbprint,
28+
'ParameterValue',
29+
$_.FriendlyName
30+
)
31+
}
32+
})]
2333
[string]
2434
$Thumbprint = (Get-ChildItem Cert:\LocalMachine\TrustedPeople -Recurse | Select-Object -ExpandProperty Thumbprint),
2535

2636
# The certificate subject that identifies the target SSL certificate in
2737
# the local machine certificate stores.
28-
[Parameter()]
38+
[Parameter(ParameterSetName='Subject')]
2939
[string]
3040
$Subject,
3141

3242
#If using a wildcard certificate, provide a DNS name you want to use to access services secured by the certificate.
33-
[Parameter()]
43+
[Parameter(ParameterSetName='Subject')]
44+
[Parameter(ParameterSetName='Thumbprint')]
3445
[string]
3546
$CertificateDnsName,
3647

@@ -44,7 +55,7 @@ param(
4455

4556
# The C4B server hostname for which to generate a new self-signed certificate.
4657
# Ignored/unused if a certificate thumbprint or subject is supplied.
47-
[Parameter()]
58+
[Parameter(ParameterSetName='SelfSigned')]
4859
[string]
4960
$Hostname = [System.Net.Dns]::GetHostName(),
5061

@@ -91,8 +102,8 @@ process {
91102
}
92103
}
93104

94-
#Nexus
95-
#Stop Services/Processes/Websites required
105+
<# Nexus #>
106+
# Stop Services/Processes/Websites required
96107
Stop-Service nexus
97108

98109
# Put certificate in TrustedPeople
@@ -113,41 +124,37 @@ process {
113124
$response = try {
114125
Invoke-WebRequest "https://${SubjectWithoutCn}:8443" -UseBasicParsing -ErrorAction Stop
115126
Start-Sleep -Seconds 3
116-
}
117-
catch {
118-
119-
}
120-
127+
} catch {}
121128
} until($response.StatusCode -eq '200')
122129
Write-Host "Nexus is ready!"
123130

124131
choco source remove --name="'ChocolateyInternal'"
125132
$RepositoryUrl = "https://${SubjectWithoutCn}:8443/repository/ChocolateyInternal/index.json"
126133

127-
#Build Credential Object, Connect to Nexus
134+
# Build Credential Object, Connect to Nexus
128135
$securePw = (Get-Content 'C:\programdata\sonatype-work\nexus3\admin.password') | ConvertTo-SecureString -AsPlainText -Force
129136
$Credential = [System.Management.Automation.PSCredential]::new('admin', $securePw)
130-
137+
131138
# Connect to Nexus
132139
Connect-NexusServer -Hostname $SubjectWithoutCn -Credential $Credential -UseSSL
133140

134141
# Add updated scripts to raw repo in Nexus
135142

136-
#Push ChocolateyInstall.ps1 to raw repo
143+
# Push ChocolateyInstall.ps1 to raw repo
137144
$ScriptDir = "$env:SystemDrive\choco-setup\files\scripts"
138145
$ChocoInstallScript = "$ScriptDir\ChocolateyInstall.ps1"
139146
(Get-Content -Path $ChocoInstallScript) -replace "{{hostname}}", $SubjectWithoutCn | Set-Content -Path $ChocoInstallScript
140147
New-NexusRawComponent -RepositoryName 'choco-install' -File "$ChocoInstallScript"
141148

142-
#Push ClientSetup.ps1 to raw repo
149+
# Push ClientSetup.ps1 to raw repo
143150
$ClientScript = "$ScriptDir\ClientSetup.ps1"
144151
(Get-Content -Path $ClientScript) -replace "{{hostname}}", $SubjectWithoutCn | Set-Content -Path $ClientScript
145152
New-NexusRawComponent -RepositoryName 'choco-install' -File $ClientScript
146153

147154
if ($Hardened) {
148155
# Disable anonymous authentication
149156
Set-NexusAnonymousAuth -Disabled
150-
157+
151158
if (-not (Get-NexusRole -Role 'chocorole' -ErrorAction SilentlyContinue)) {
152159
# Create Nexus role
153160
$RoleParams = @{
@@ -202,6 +209,34 @@ process {
202209
$chocoArgs = @('apikey', "--source='$RepositoryUrl'", "--api-key='$NuGetApiKey'")
203210
& choco @chocoArgs
204211

212+
Update-JsonFile -Path "$env:SystemDrive\choco-setup\logs\nexus.json" -Properties @{
213+
NexusUri = "https://$($SubjectWithoutCn):8443"
214+
NexusRepo = $RepositoryUrl
215+
ChocoUserPassword = $NexusPw
216+
}
217+
218+
<# Jenkins #>
219+
$JenkinsHome = "C:\ProgramData\Jenkins\.jenkins"
220+
221+
# Update Jenkins Jobs with Nexus URL
222+
Get-ChildItem -Path "$JenkinsHome\jobs" -Recurse -File -Filter 'config.xml' | Invoke-TextReplacementInFile -Replacement @{
223+
'(?<=https:\/\/)(?<HostName>.+)(?=:8443\/repository\/)' = $SubjectWithoutCn
224+
}
225+
226+
# Generate Jenkins keystore
227+
Set-JenkinsCertificate -Thumbprint $Certificate.Thumbprint
228+
229+
# Add firewall rule for Jenkins
230+
netsh advfirewall firewall add rule name="Jenkins-7443" dir=in action=allow protocol=tcp localport=7443
231+
232+
Update-JsonFile -Path "$env:SystemDrive\choco-setup\logs\jenkins.json" -Properties @{
233+
JenkinsUri = "https://$($SubjectWithoutCn):7443"
234+
}
235+
236+
<# CCM #>
237+
# Update the service certificate
238+
Set-CcmCertificate -CertificateThumbprint $Certificate.Thumbprint
239+
205240
# Remove old CCM web binding, and add new CCM web binding
206241
Stop-CcmService
207242
Remove-CcmBinding
@@ -282,7 +317,13 @@ Invoke-Expression (`$downloader.DownloadString("http://`$(`$HostName):80/Import-
282317
(Get-Content -Path $EndpointScript) -replace "# placeholder if using a self-signed cert", $ScriptBlock | Set-Content -Path $EndpointScript
283318
}
284319
}
285-
320+
321+
Update-JsonFile -Path "$env:SystemDrive\choco-setup\logs\ccm.json" -Properties @{
322+
CCMWebPortal = "https://$($SubjectWithoutCn)/Account/Login"
323+
CCMServiceURL = "https://$($SubjectWithoutCn):24020/ChocolateyManagementService"
324+
ServiceSalt = $ServiceSaltValue
325+
ClientSalt = $ClientSaltValue
326+
}
286327

287328
# Save useful params to JSON
288329
$SslJson = @{
@@ -299,6 +340,47 @@ end {
299340
# Hand back the created/found certificate to the caller.
300341
$Certificate
301342

343+
Write-Host 'Writing README to Desktop; this file contains login information for all C4B services.'
344+
New-QuickstartReadme
345+
346+
Write-Host 'Cleaning up temporary data'
347+
Remove-JsonFiles
348+
349+
$Message = 'The CCM, Nexus & Jenkins sites will open in your browser in 10 seconds. Press any key to skip this.'
350+
$Timeout = New-TimeSpan -Seconds 10
351+
$Stopwatch = [System.Diagnostics.Stopwatch]::new()
352+
$Stopwatch.Start()
353+
Write-Host $Message -NoNewline -ForegroundColor Green
354+
do {
355+
# wait for a key to be available:
356+
if ([Console]::KeyAvailable) {
357+
# read the key, and consume it so it won't
358+
# be echoed to the console:
359+
$keyInfo = [Console]::ReadKey($true)
360+
Write-Host "`nSkipping the Opening of sites in your browser." -ForegroundColor Green
361+
# exit loop
362+
break
363+
}
364+
# write a dot and wait a second
365+
Write-Host '.' -NoNewline -ForegroundColor Green
366+
Start-Sleep -Seconds 1
367+
}
368+
while ($Stopwatch.Elapsed -lt $Timeout)
369+
$Stopwatch.Stop()
370+
371+
if (-not ($keyInfo)) {
372+
Write-Host "`nOpening CCM, Nexus & Jenkins sites in your browser." -ForegroundColor Green
373+
$Readme = 'file:///C:/Users/Public/Desktop/README.html'
374+
$Ccm = "https://$($SubjectWithoutCn)/Account/Login"
375+
$Nexus = "https://$($SubjectWithoutCn):8443"
376+
$Jenkins = "https://$($SubjectWithoutCn):7443"
377+
try {
378+
Start-Process msedge.exe "$Readme", "$Ccm", "$Nexus", "$Jenkins"
379+
} catch {
380+
Start-Process chrome.exe "$Readme", "$Ccm", "$Nexus", "$Jenkins"
381+
}
382+
}
383+
302384
$ErrorActionPreference = $DefaultEap
303385
Stop-Transcript
304386
}

Start-C4bJenkinsSetup.ps1

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ C4B Quick-Start Guide Jenkins setup script
1111
[CmdletBinding()]
1212
param(
1313
# Hostname of your C4B Server
14-
[string]$HostName = $(Get-Content "$env:SystemDrive\choco-setup\logs\ssl.json" | ConvertFrom-Json).CertSubject,
14+
[string]$HostName = $env:ComputerName,
1515
# Repo where you're installing Jenkins from, usually CCR
1616
[string]$Source = 'https://community.chocolatey.org/api/v2/',
1717
# API key of your Nexus repo, for Chocolatey Jenkins jobs to use
@@ -56,14 +56,8 @@ process {
5656
$JenkinsVersion | Out-File -FilePath $JenkinsHome\jenkins.install.UpgradeWizard.state -Encoding utf8
5757
$JenkinsVersion | Out-File -FilePath $JenkinsHome\jenkins.install.InstallUtil.lastExecVersion -Encoding utf8
5858

59-
# Set the external hostname, such that it's ready for use. This may change, but we've pinned Jenkin's version.
60-
@"
61-
<?xml version='1.1' encoding='UTF-8'?>
62-
<jenkins.model.JenkinsLocationConfiguration>
63-
<adminAddress>address not configured yet &lt;nobody@nowhere&gt;</adminAddress>
64-
<jenkinsUrl>http://$($HostName):8080</jenkinsUrl>
65-
</jenkins.model.JenkinsLocationConfiguration>
66-
"@ | Out-File -FilePath $JenkinsHome\jenkins.model.JenkinsLocationConfiguration.xml -Encoding utf8
59+
# Set the hostname, such that it's ready for use.
60+
Set-JenkinsLocationConfiguration -Url "http://$($HostName):8080" -Path $JenkinsHome\jenkins.model.JenkinsLocationConfiguration.xml
6761

6862
#region Set Jenkins Password
6963
$JenkinsCred = Set-JenkinsPassword -UserName 'admin' -NewPassword $(New-ServicePassword) -PassThru
@@ -146,14 +140,11 @@ process {
146140

147141
#region Job Config
148142
Write-Host "Creating Chocolatey Jobs" -ForegroundColor Green
149-
Get-ChildItem "$env:SystemDrive\choco-setup\files\jenkins" | Copy-Item -Destination "$JenkinsHome\jobs\" -Recurse
143+
Get-ChildItem "$env:SystemDrive\choco-setup\files\jenkins" | Copy-Item -Destination "$JenkinsHome\jobs\" -Recurse -Force
150144

151-
152-
Get-ChildItem -Path "$JenkinsHome\jobs" -Recurse -File -Filter 'config.xml' | ForEach-Object {
153-
(Get-Content -Path $_.FullName -Raw) -replace
154-
'{{NugetApiKey}}', $NuGetApiKey -replace
155-
'{{hostname}}', $HostName |
156-
Set-Content -Path $_.FullName
145+
Get-ChildItem -Path "$JenkinsHome\jobs" -Recurse -File -Filter 'config.xml' | Invoke-TextReplacementInFile -Replacement @{
146+
'{{NugetApiKey}}' = $NuGetApiKey
147+
'(?<=https:\/\/)(?<HostName>.+)(?=:8443\/repository\/)' = $HostName
157148
}
158149
#endregion
159150

@@ -169,52 +160,10 @@ process {
169160
$JenkinsJson | ConvertTo-Json | Out-File "$env:SystemDrive\choco-setup\logs\jenkins.json"
170161

171162
Write-Host 'Jenkins setup complete' -ForegroundColor Green
172-
Write-Host 'Login to Jenkins at: http://$($HostName):8080' -ForegroundColor Green
163+
Write-Host "Login to Jenkins at: $($JenkinsJson.JenkinsUri)" -ForegroundColor Green
173164
Write-Host 'Initial default Jenkins admin user password:' -ForegroundColor Green
174165
Write-Host "Admin Password is '$($JenkinsJson.JenkinsPw)'" -ForegroundColor Green
175166

176-
Write-Host 'Writing README to Desktop; this file contains login information for all C4B services.'
177-
New-QuickstartReadme
178-
179-
Write-Host 'Cleaning up temporary data'
180-
Remove-JsonFiles
181-
182-
$Message = 'The CCM, Nexus & Jenkins sites will open in your browser in 10 seconds. Press any key to skip this.'
183-
$Timeout = New-TimeSpan -Seconds 10
184-
$Stopwatch = [System.Diagnostics.Stopwatch]::new()
185-
$Stopwatch.Start()
186-
Write-Host $Message -NoNewline -ForegroundColor Green
187-
do {
188-
# wait for a key to be available:
189-
if ([Console]::KeyAvailable) {
190-
# read the key, and consume it so it won't
191-
# be echoed to the console:
192-
$keyInfo = [Console]::ReadKey($true)
193-
Write-Host "`nSkipping the Opening of sites in your browser." -ForegroundColor Green
194-
# exit loop
195-
break
196-
}
197-
# write a dot and wait a second
198-
Write-Host '.' -NoNewline -ForegroundColor Green
199-
Start-Sleep -Seconds 1
200-
}
201-
while ($Stopwatch.Elapsed -lt $Timeout)
202-
$Stopwatch.Stop()
203-
204-
if (-not ($keyInfo)) {
205-
Write-Host "`nOpening CCM, Nexus & Jenkins sites in your browser." -ForegroundColor Green
206-
$Readme = 'file:///C:/Users/Public/Desktop/README.html'
207-
$Ccm = "https://${hostname}/Account/Login"
208-
$Nexus = "https://${hostname}:8443"
209-
$Jenkins = 'http://localhost:8080'
210-
try {
211-
Start-Process msedge.exe "$Readme", "$Ccm", "$Nexus", "$Jenkins"
212-
}
213-
catch {
214-
Start-Process chrome.exe "$Readme", "$Ccm", "$Nexus", "$Jenkins"
215-
}
216-
}
217-
218167
$ErrorActionPreference = $DefaultEap
219168
Stop-Transcript
220169
}

Start-C4bSetup.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,13 @@ process {
180180
Set-Location "$env:SystemDrive\choco-setup\files"
181181
.\Start-C4BNexusSetup.ps1
182182
.\Start-C4bCcmSetup.ps1 -DatabaseCredential $DatabaseCredential
183+
.\Start-C4bJenkinsSetup.ps1
183184
if ($Thumbprint) {
184185
.\Set-SslSecurity.ps1 -Thumbprint $Thumbprint
185186
}
186187
else {
187188
.\Set-SslSecurity.ps1
188189
}
189-
.\Start-C4bJenkinsSetup.ps1
190190
}
191191

192192
$ErrorActionPreference = $DefaultEap

0 commit comments

Comments
 (0)