-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsetup-nexus.yml
443 lines (399 loc) · 15.3 KB
/
setup-nexus.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
---
- name: Add FQDN to Hostsfile
community.windows.win_hosts:
canonical_name: "{{ nexus_fqdn }}"
ip_address: 127.0.0.1
- name: Install Nexus
chocolatey.chocolatey.win_chocolatey:
name: nexus-repository
state: latest
package_params:
- "/PORT={{ nexus_port | default(8081) }}"
- name: Set Nexus Certificate
when: certificate_path is defined
block:
- name: Ensure Directory
ansible.windows.win_file:
path: C:\choco-setup\
state: directory
- name: Copy Certificate to Disk
ansible.windows.win_copy:
src: "{{ certificate_path }}"
dest: C:\choco-setup\nexus.pfx
register: certificate_copy
- name: Install Nexus Certificate
when: certificate_copy.changed
ansible.windows.win_powershell:
parameters:
NexusPort: "{{ nexus_port | default(8081) }}"
CertificatePath: "{{ certificate_copy.dest }}"
CertificatePassword: "{{ certificate_password }}"
script: |
param($NexusPort, $CertificatePath, $CertificatePassword)
# Check that the certificate and password match
try {
$null = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
$CertificatePath,
$CertificatePassword,
32 # EphemeralKeySet
)
} catch {
$Ansible.Result = "Certificate and Password do not match"
$Ansible.Failed = $true
}
# Generate the Keystore file
$KeyStore = "C:\ProgramData\nexus\etc\ssl\keystore.jks"
$KeyTool = "C:\ProgramData\nexus\jre\bin\keytool.exe"
$XmlPath = 'C:\ProgramData\nexus\etc\jetty\jetty-https.xml'
$Passkey = '{{ lookup('ansible.builtin.password', '/dev/null', chars=['ascii_letters', 'digits'], length=32, seed=certificate_password+inventory_hostname) }}'
if (Test-Path $KeyStore) {
Remove-Item $KeyStore -Force
}
$CurrentAlias = ($($CertificatePassword | & $KeyTool -list -v -storetype PKCS12 -keystore $CertificatePath) -match "^Alias.*")[0].Split(':')[1].Trim()
& $KeyTool -importkeystore -srckeystore $CertificatePath -srcstoretype PKCS12 -srcstorepass $CertificatePassword -destkeystore $KeyStore -deststoretype JKS -alias $currentAlias -destalias jetty -deststorepass $passkey
& $KeyTool -keypasswd -keystore $KeyStore -alias jetty -storepass $passkey -keypass $CertificatePassword -new $passkey
# Update the Jetty XML Configuration
[xml]$Xml = Get-Content -Path $XmlPath
$Xml.Configure.New.Where{
$_.id -match 'ssl'
}.Set.Where{
$_.name -match 'password'
}.ForEach{
$_.InnerText = $passkey
}
$Xml.Save($XmlPath)
# Update the Nexus Configuration
$configPath = "C:\ProgramData\sonatype-work\nexus3\etc\nexus.properties"
(Get-Content $configPath) | Where-Object {$_ -notmatch "application-port-ssl="} | Set-Content $configPath
@(
'jetty.https.stsMaxAge=-1'
"application-port-ssl=$NexusPort"
'nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-https.xml,${jetty.etc}/jetty-requestlog.xml'
).ForEach{
if ((Get-Content -Raw $configPath) -notmatch [regex]::Escape($_)) {
$_ | Add-Content -Path $configPath
}
}
if ((Get-Service nexus).Status -eq 'Running') {
Restart-Service nexus
} else {
Start-Service nexus
}
- name: Wait for Nexus
ansible.windows.win_wait_for:
delay: 10
host: localhost
port: "{{ nexus_port }}"
- name: Add Firewall Exception for Nexus
community.windows.win_firewall_rule:
name: Nexus
action: allow
description: Allow inbound traffic to the Nexus service
localport: "{{ nexus_port | default(8081) }}"
protocol: tcp
- name: Check for First Run
ansible.windows.win_stat:
path: "C:\\ProgramData\\sonatype-work\\nexus3\\admin.password"
register: _firstrun_file
- name: Get Admin Credentials for Nexus
when: _firstrun_file.stat.exists
block:
- name: Get Default Nexus Password
ansible.windows.win_powershell:
script: |
$Ansible.Result = if (Test-Path C:\ProgramData\sonatype-work\nexus3\admin.password) {
"$(Get-Content C:\ProgramData\sonatype-work\nexus3\admin.password)"
} else {
"{{ nexus_password }}"
}
register: _token
- name: Set Nexus Password using Default Password
ansible.windows.win_uri:
url: "https://{{ nexus_fqdn | default('localhost') }}:{{ nexus_port | default(8081) }}/service/rest/v1/security/users/admin/change-password"
method: PUT
headers:
Content-Type: "text/plain"
Authorization: "Basic {{ (('admin:' + (_token.result | string()))) | b64encode }}"
body: "{{ nexus_password }}"
status_code: 204
no_log: false # Temp
- name: Test Nexus Credential
ansible.windows.win_uri:
url: "https://{{ nexus_fqdn | default('localhost') }}:{{ nexus_port | default(8081) }}/service/rest/v1/status"
method: GET
headers:
Authorization: "Basic {{ (('admin:' + (nexus_password | string()))) | b64encode }}"
register: _credential_test
- name: Remove Default Password File
ansible.windows.win_file:
path: "C:\\ProgramData\\sonatype-work\\nexus3\\admin.password"
state: absent
when: _credential_test.status_code == 200
- name: Set Credentials for Nexus
ansible.builtin.set_fact:
_baseurl: "https://{{ nexus_fqdn | default('localhost') }}:{{ nexus_port | default(8081) }}/service/rest/v1"
_base64_token: "{{ (('admin:' + (nexus_password | string()))) | b64encode }}"
- name: Disable Anonymous Authentication
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/anonymous"
method: PUT
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
body:
enabled: false
userId: anonymous
realmName: NexusAuthorizingRealm
- name: Enable Nuget Api-Key Realm
block:
- name: Get Current Realms
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/realms/active"
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
return_content: true
register: _current_realms
- name: Enable Nuget API Key Realm
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/realms/active"
method: PUT
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
body: "{{ ['NuGetApiKey'] + _current_realms.json | list }}"
status_code: 204
when: "'NuGetApiKey' not in _current_realms.json | list"
- name: Create Roles
block:
- name: Get Existing Roles
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/roles"
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
return_content: true
status_code:
- 200 # It may exist
- 404 # It may not exist
register: _existing_roles
- name: Create Role
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/roles"
method: POST
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
body:
id: "{{ item.name }}"
name: "{{ item.name }}"
description: "{{ item.description }}"
privileges: "{{ item.privileges }}"
roles: []
when: item.name not in _existing_roles.json | map(attribute='id') | list
loop:
- name: chocoweb
description: Role for web enabled choco clients
privileges:
- nx-repository-view-nuget-*-browse
- nx-repository-view-nuget-*-read
- nx-repository-view-raw-*-read
- nx-repository-view-raw-*-browse
- name: package-uploader
description: Role allowed to push and list packages
privileges:
- nx-repository-view-nuget-*-edit
- nx-repository-view-nuget-*-read
- nx-apikey-all
- name: Create Users
block:
- name: Get Existing Users
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/users"
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
return_content: true
register: _existing_users
- name: Create User
ansible.windows.win_uri:
url: "{{ _baseurl }}/security/users"
method: POST
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
body: "{{ item }}"
loop:
- userId: chocouser
firstName: Choco
lastName: Webuser
emailAddress: chocouser@{{ inventory_hostname }}
password: "{{ chocouser_password }}"
status: Active
roles: ['chocoweb']
- userId: chocopackager
firstName: Chocolatey
lastName: Packager
emailAddress: chocopackager@{{ inventory_hostname }}
password: "{{ packageuser_password }}"
status: Active
roles: ['package-uploader']
when: item.userId not in _existing_users.json | map(attribute='userId') | list
no_log: true
- name: Create API Key for chocopackager
block:
- name: Get User Token
ansible.windows.win_uri:
url: "https://{{ nexus_fqdn }}:{{ nexus_port | default(8081) }}/service/extdirect"
method: POST
headers:
Content-Type: "application/json"
Authorization: "Basic {{ (('chocopackager:' + (packageuser_password | string()))) | b64encode }}"
body:
action: rapture_Security
method: authenticationToken
data: ["{{ 'chocopackager' | b64encode }}", "{{ packageuser_password | b64encode }}"]
type: rpc
tid: 16
return_content: true
register: _packager_usertoken
- name: Set Facts for Api-Key retrieval
ansible.builtin.set_fact:
_packager_usertoken: "{{ _packager_usertoken.json.result.data | b64encode }}"
_dc_string: "1625090000000"
- name: Get NuGet API-Key for chocopackager
ansible.windows.win_uri:
url: "https://{{ nexus_fqdn }}:{{ nexus_port | default(8081) }}/service/rest/internal/nuget-api-key?authToken={{ _packager_usertoken }}&_dc={{ _dc_string }}"
method: GET
headers:
Content-Type: "application/json"
Authorization: "Basic {{ (('chocopackager:' + (packageuser_password | string()))) | b64encode }}"
return_content: true
register: _packager_apikey
- name: Set Credential File
ansible.builtin.copy:
dest: credentials/nexus_apikey
content: "{{ _packager_apikey.json.apiKey }}"
delegate_to: localhost
- name: Set up Repositories
block:
- name: Get Existing Repositories
ansible.windows.win_uri:
url: "{{ _baseurl }}/repositories"
method: GET
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
return_content: true
register: _existing_repositories
- name: Remove Default Repositories
ansible.windows.win_uri:
url: "{{ _baseurl }}/repositories/{{ item }}"
method: DELETE
headers:
Authorization: "Basic {{ _base64_token }}"
status_code: 204
loop:
- 'nuget-group'
- 'maven-snapshots'
- 'maven-central'
- 'nuget.org-proxy'
- 'maven-releases'
- 'nuget-hosted'
- 'maven-public'
when: item in _existing_repositories.json | default([]) | map(attribute='name') | list
- name: Calculate Required Repositories
ansible.builtin.set_fact:
_nexus_repositories: "{{ default_repositories + chocosetup if hostvars['localhost']['existing_packages']['files'] | length > 0 else default_repositories }}"
vars:
default_repositories:
- name: ChocolateyInternal
type: nuget
- name: ChocolateyTest
type: nuget
- name: choco-install
type: raw
chocosetup:
- name: ChocolateySetup
type: nuget
- name: Create Repositories
ansible.windows.win_uri:
url: "{{ _baseurl }}/repositories/{{ item.type }}/hosted"
method: POST
headers:
Content-Type: "application/json"
Authorization: "Basic {{ _base64_token }}"
body:
name: "{{ item.name }}"
online: true
storage:
blobStoreName: default
writePolicy: Allow
strictContentTypeValidation: true
status_code: 201
when: item.name not in _existing_repositories.json | default([]) | map(attribute='name') | list
loop: "{{ _nexus_repositories }}"
- name: Install NexuShell
chocolatey.chocolatey.win_chocolatey:
name: NexuShell
state: present
- name: Drop Install Scripts
ansible.windows.win_template:
src: templates/{{ item }}.ps1.j2
dest: C:\choco-setup\{{ item }}.ps1
loop:
- ClientSetup
- ChocolateyInstall
- name: Populate Nexus Repositories
ansible.windows.win_powershell:
parameters:
BaseDirectory: 'C:\choco-setup'
RawFiles:
- ChocolateyInstall.ps1
- ClientSetup.ps1
Packages:
- chocolatey
- chocolatey.extension
- chocolateygui
- chocolateygui.extension
- chocolatey-agent
- chocolatey-compatibility.extension
- chocolatey-core.extension
- chocolatey-dotnetfx.extension
- dotnetfx
- KB2919355
- KB2919442
script: |
param($BaseDirectory, [string[]]$RawFiles, [string[]]$Packages)
$Credential = [PSCredential]::new("admin", ("{{ nexus_password }}" | ConvertTo-SecureString -AsPlainText -Force))
Connect-NexusServer -Hostname '{{ nexus_fqdn }}' -Sslport '{{ nexus_port }}' -Credential $Credential -UseSSL
$Ansible.Changed = $false
Set-Location $BaseDirectory
$ApiToken = (Get-NexusNuGetApiKey -Credential $Credential).apiKey
# Handle Chocolatey Packages
$Repo = @{RepositoryName = "ChocolateyInternal"}
$ExistingPackages = Get-NexusComponent @Repo
foreach ($Package in $Packages) {
$Path = @(Convert-Path "$BaseDirectory\$($Package).*.nupkg") -match "$($Package)\.\d"
if ($Package -notin $ExistingPackages.Name) {
if (-not $Path) {
choco download $Package --source="chocolatey,chocolatey.licensed"
$Path = @(Convert-Path "$BaseDirectory\$($Package).*.nupkg") -match "$($Package)\.\d"
}
$Ansible.Changed = $true
foreach ($Path in $Path) {
choco push $Path --source https://{{ nexus_fqdn }}:{{ nexus_port }}/repository/ChocolateyInternal/ --api-key $ApiToken
}
}
}
# Handle Raw Assets
$Repo.RepositoryName = "choco-install"
$ExistingRawFiles = Get-NexusComponent @Repo
foreach ($File in $RawFiles) {
$Path = Join-Path $BaseDirectory $File
if ($File -notin $ExistingRawFiles.Name -and (Test-Path $Path)) {
$Ansible.Changed = $true
New-NexusRawComponent @Repo -File $Path
}
}
...