Skip to content

Commit

Permalink
Re-host Nexus on vm (#1584)
Browse files Browse the repository at this point in the history
* Initial commit

* Replaced webapp with vm

* Amended docker start commands

* Amended firewall

* Add nexus config to persistent volume

* Add private dns zone

* Corrected rg var

* Added Nexus letsencrypt cert gen

* Fixed linting

* Changed terraform.lock.hcl to previous version

* Removed leftover debug

* Typo fix

Co-authored-by: Stuart Leeks <[email protected]>

* File path amend

Co-authored-by: Stuart Leeks <[email protected]>

* Fix for cloudapp DNS resolution errors

* Docker running on Nexus VM

* Documented Letsencrypt process

* Permissions fix

* Typo fix

Co-authored-by: Stuart Leeks <[email protected]>

* Typo fix

Co-authored-by: Stuart Leeks <[email protected]>

* Typo fix

Co-authored-by: Stuart Leeks <[email protected]>

* Formatting changes

* Added reference to letsencrypt doc

* Added new page reference

* Moved password generation for nexus to tf

* Write script to fs first before execution

* Password reset finally working

* Make config nexus script runnable from any dir

* Added basic status info

* Fix recursive file loop

* Typo fix

* Updated docs

* renamed env file

* Fix typo

* Added new nexus fqdn to user resources

* Add vnet link to workspaces

* Bump versions

* Removed nexus properties file

* Updated execution permissions

* Get cert in tf

* Added az cli get cert

* Amended prune job

* Added msi id to login

* Amended msi and exported cert pwd

* Jetty configuration

* Escape jetty vars

* Password script fixes

* Amended networking to use module

* Use https in config script

* Removed res proc location variable

* Potential linting fix

* Linting fixes

* Linting directive positioning

* Gitea version bump

* Terraform format

* Reorder linting to workaround superlinter bug with Terraform

* Added nexus-cert to build and caching of letsencrypt

* Adopted new shared service deploy method

* Added cron job to renew nexus cert

* Removed location references

* And another

* Removed location refs and added az cli

* Fixed nexus-cert kv permissions

* Corrected outputs directory

* Fixed shared service deployment steps

* Updated docs and removed renew prompt

* version bump

* Increase bundle versions

* remote location from variables files

* Removed shared service make

* Removed docker prune

* Bash headers

* Layer clean

* Reduce layer

* Testing without kv role assignment

* Removed kv role assignment

* Adding firewall rule to allow letsencrypt from RP

* Genericised cert service and added letsencrypt action

* Fixed auth hook

* Removed make commands

* Certbot in bundle container

* Tidied naming

* Python base image

* Generate action successful

* Inject cert name to nexus bundle

* Implemented app gateway start/stop

* Separated cloudinit yaml into scripts

* Fixed new line issue

* Fixed bash casing

* Added local nexus repo config

* Added retry logic to config repos

* gitea bump

* Fixed status code

* terraform linting

* Added docs

* Lint fix

* Update docs/tre-developers/letsencrypt.md

* Update docs/tre-admins/setup-instructions/configuring-shared-services.md

* Update docs/tre-developers/letsencrypt.md

* Update docs/tre-developers/letsencrypt.md

* Update docs/tre-admins/setup-instructions/configuring-shared-services.md

Co-authored-by: Marcus Robinson <[email protected]>

* Fix firewall conflict

* Added note to docs for cert kv conflicts

* Renamed sonatype-nexus to nexus for new version

* Added old nexus service code

* Lint fix

* Renamed folder to be obvious as the nexus-vm

* Added docs for upgrade path

* Added data.azurerm rg core

* linting

* bash linting

* Require workspace of 0.2.14 or above

* Moved new version notes to section below config steps

* Removed give new cert name

* RP cert permissions

* tf format

* Added required params for certs and nexus tempalte schema

* Added cert import permissions

* Added certs delete permission

* App gateway az login

* Version bumps

* tf fmt

* Added missing az cred params to certs

* Add purge permission

* Bump tf versions to 3.4.0 & set purge to false

* Removed unsupported property from new provider

* Moved nexus private zone to core

* Amended location var

* Amended zone location

* Added upgrade flag for tf

* Remove tf lock

* Added new tf key

* Added key into uninstall

* Resolve firewall rule conflicts

* Var reference fix

* Fix for potential @ symbol in nexus admin password causing curl bug

* Added nexus_version variable to user resources for back compat

* Added docs for nexus_version

* downgrade superlinter

* revert superlinter to v4

* Remove lint aws plugin block

* Use superlinter latest

* Manually set tflint path

Co-authored-by: oliver7598 <[email protected]>
Co-authored-by: Stuart Leeks <[email protected]>
Co-authored-by: Ross Smith <[email protected]>
Co-authored-by: ross-p-smith <[email protected]>
Co-authored-by: Jamie D <[email protected]>
Co-authored-by: Stuart Leeks <[email protected]>
Co-authored-by: marrobi <[email protected]>
  • Loading branch information
8 people authored May 26, 2022
1 parent 7f5a5ac commit 350d8a0
Show file tree
Hide file tree
Showing 77 changed files with 2,099 additions and 34 deletions.
5 changes: 0 additions & 5 deletions .github/linters/.tflint.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ config {
force = false
}

# https://github.com/github/super-linter/issues/2954
plugin "aws" {
enabled = false # Override: disable AWS
}

plugin "azurerm" {
enabled = true
}
7 changes: 5 additions & 2 deletions .github/workflows/build_validation_develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,17 @@ jobs:
if: ${{ steps.filter.outputs.terraform == 'true' }}
run: |
find . -type d -name 'terraform' -not -path '*cnab*' -print0 \
| xargs -0 -I{} sh -c 'echo "***** Validating: {} *****"; \
| xargs -0 -I{} sh -c 'echo "***** Validating: {} *****"; \https://github.com/github/super-linter/issues/2433
terraform -chdir={} init -backend=false; terraform -chdir={} validate'
- name: Lint code base
# the slim image is 2GB smaller and we don't use the extra stuff
# Moved this after the Terraform checks above due something similar to this issue: https://github.com/github/super-linter/issues/2433
uses: github/super-linter/[email protected].2
uses: github/super-linter/[email protected].3
env:
# Until https://github.com/github/super-linter/commit/ec0662756da93f1e3aad4df049712df7d764d143 is released
# we need to set the correct plugin directory (which is incorrectly set to github/home/.tflint.d/plugins by default)
TFLINT_PLUGIN_DIR: "/root/.tflint.d/plugins"
VALIDATE_ALL_CODEBASE: false
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
107 changes: 101 additions & 6 deletions docs/tre-admins/setup-instructions/configuring-shared-services.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,117 @@
# Configuring Shared Services

Complete the configuration of the shared services (Nexus and Gitea) from inside of the TRE environment.
## Deploy/configure Nexus

Make sure you run the following command using git bash and set your current directory as C:/AzureTRE
If you're deploying a brand new environment you should deploy the VM-based (V2) service (read section `A`). If you wish to migrate from an existing App Service Nexus service (V1) to the VM-based service, first deploy the new service (section `A`) then proceed to section `B`.

## Configure Nexus repository
!!! info
The Makefile commands for deploying shared services temporarily target the V1 service so that existing environments won't have a new V2 Nexus service deployed automatically by CICD and introduce breaking changes. The V2 Nexus service will need to be deployed manually using the steps below.

1. Run the Nexus configuration script to reset the password and setup a PyPI proxy on Nexus:
```./templates/shared_services/sonatype-nexus/scripts/configure_nexus.sh -t <tre_id>```
### A. Deploy & configure V2 Nexus service (hosted on VM)

## Configure Gitea repository
!!! caution
Before deploying the V2 Nexus service, you will need workspaces of version `0.3.2` or above due to a dependency on a DNS zone link for the workspace(s) to connect to the Nexus VM.

Before deploying the Nexus shared service, you need to make sure that it will have access to a certificate to configure serving secure proxies. By default, the Nexus service will serve proxies from `https://nexus-{TRE_ID}.{LOCATION}.cloudapp.azure.com/`, and thus it requires a certificate that validates ownership of this domain to use for SSL.

You can use the Certs Shared Service to set one up by following these steps:

1. Run the below commands in your terminal to build, publish and register the certs bundle:

```cmd
make bundle-build DIR=./templates/shared_services/certs
make bundle-publish DIR=./templates/shared_services/certs
make bundle-register DIR=./templates/shared_services/certs BUNDLE_TYPE=shared_service
```

2. Navigate to the Swagger UI for your TRE API at `https://<azure_tre_fqdn>/api/docs`, and authenticate if you haven't already by clicking `Authorize`.

3. Click `Try it out` on the `POST` `/api/shared-services` operation, and paste the following to deploy the certs service:

```json
{
"templateName": "tre-shared-service-certs",
"properties": {
"display_name": "Nexus cert",
"description": "Generate/renew ssl cert for Nexus shared service",
"domain_prefix": "nexus",
"cert_name": "nexus-ssl"
}
}
```

!!! caution
If you have KeyVault Purge Protection enabled and are re-deploying your environment using the same `cert_name`, you may encounter this: `Status=409 Code=\"Conflict\" Message=\"Certificate nexus-ssl is currently in a deleted but recoverable state`. You need to either manually recover the certificate or purge it before redeploying.

1. Once the shared service has been deployed (which you can check by querying the `/api/shared-services/operations` method), copy its `resource_id`, then find the `POST` operation for `/api/shared-services/{shared_service_id}/invoke_action`, click `Try it out` and paste in the resource id into the `shared_service_id` field, and enter `generate` into the `action` field, then click `Execute`.

This will invoke the certs service to use Letsencrypt to generate a certificate for the specified domain prefix followed by `-{TRE_ID}.{LOCATION}.cloudapp.azure.com`, so in our case, having entered `nexus`, this will be `nexus-{TRE_ID}.{LOCATION}.cloudapp.azure.com`, which will be the public domain for our Nexus service.

Once this has completed, you can verify its success either from the operation output, or by navigating to your core keyvault (`kv-{TRE_ID}`) and looking for a certificate called `nexus-ssl` (or whatever you called it).

After verifying the certificate has been generated, you can deploy Nexus:

1. Run the below commands in your terminal to build, publish and register the Nexus shared service bundle:

```cmd
make bundle-build DIR=./templates/shared_services/sonatype-nexus-vm
make bundle-publish DIR=./templates/shared_services/sonatype-nexus-vm
make bundle-register DIR=./templates/shared_services/sonatype-nexus-vm BUNDLE_TYPE=shared_service
```

1. Navigate to the Swagger UI for your TRE API at `https://<azure_tre_fqdn>/api/docs`, and authenticate if you haven't already by clicking `Authorize`.

1. Click `Try it out` on the `POST` `/api/shared-services` operation, and paste the following to deploy the Nexus shared service:

```json
{
"templateName": "tre-shared-service-sonatype-nexus",
"properties": {
"display_name": "Nexus",
"description": "Proxy public repositories with Nexus",
"ssl_cert_name": "nexus-ssl"
}
}
```

!!! tip
If you called your cert something different in the certs shared service step, make sure that is reflected above.

This will deploy the infrastructure required for Nexus, then start the service and configure it with the repository configurations located in the `./templates/shared_services/sonatype-nexus-vm/scripts/nexus_repos_config` folder. It will also set up HTTPS using the certificate you generated in the previous section, so proxies can be served at `https://nexus-{TRE_ID}.{LOCATION}.cloudapp.azure.com`.

You can optionally go to the Nexus web interface by visiting `https://nexus-{TRE_ID}.{LOCATION}.cloudapp.azure.com/` in the jumpbox and signing in with the username `admin` and the password secret located in your core keyvault, with the key `nexus-admin-password`. Here you should be able to see all of the configured repositories and you can use the UI to manage settings etc.

Just bear in mind that if this service is redeployed any changes in the UI won't be persisted. If you wish to add new repositories or alter existing ones, use the JSON files within the `./nexus_repos_config` directory.

### B. Migrate from an existing V1 Nexus service (hosted on App Service)

Once you've created the new V2 (VM-based) Nexus service by following section `A`, you can migrate from the V1 Nexus service by following these steps:

1. Identify any existing Guacamole user resources that are using the old proxy URL (`https://nexus-{TRE_ID}.azurewebsites.net/`). These will be any VMs with bundle versions < `0.3.2`.

1. These will need to be either **re-deployed** with the new template versions `0.3.2` or later and specifying an additional template parameter `"nexus_version"` with the value of `"V2"`, or manually have their proxy URLs updated by remoting into the VMs and updating the various configuration files of required package managers with the new URL (`https://nexus-{TRE_ID}.{LOCATION}.cloudapp.azure.com/`).

1. For example, pip will need the `index`, `index-url` and `trusted-host` values in the global `pip.conf` file to be modified to use the new URL.

2. Once you've confirmed there are no dependencies on the old Nexus shared service, you can delete it using the API.

### Upgrade notes

The new V2 Nexus shared service can be located in the `./templates/shared_services/sonatype-nexus-vm` directory, with the bundle name `tre-shared-service-sonatype-nexus`, which is now hosted using a VM to enable additional configuration required for proxying certain repositories.

This has been created as a separate service as the domain name exposed for proxies will be different to the one used by the original Nexus service and thus will break any user resources configured with the old proxy URL.

The original Nexus service that runs on App Service (located in `./templates/shared_services/sonatype-nexus`) has the bundle name `tre-shared-service-nexus` so can co-exist with the new VM-based shared service to enable smoother upgrading of existing resources.

## Configure Gitea repositories

Note : This is a Gitea *shared service* which will be accessible from all workspaces intended for mirroring external Git repositories. A Gitea *workspace service* can also be deployed per workspace to enable Gitea to be used within a specific workspace.

By default, this Gitea instance does not have any repositories configured. You can add repositories to Gitea either by using the command line or by using the Gitea web interface.


### Command Line
Make sure you run the following commands using git bash and set your current directory as C:/AzureTRE.

1. On the jumbox, run:
```./scripts/gitea_migrate_repo.sh -t <tre_id> -g <URL_of_github_repo_to_migrate>```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,5 @@ Workspace level operations can now be carried out using the workspace API, at `/

## Next steps

* [Installing a workspace service](./installing-workspace-service-and-user-resource.md)
* [Configuring shared services](./configuring-shared-services.md)
* [Installing a workspace service & user resources](./installing-workspace-service-and-user-resource.md)
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ You can also follow the progress in Azure portal as various resources come up.
Once the workspace service has been created, we can use the workspace API to create a user resource in our workspace.
!!! caution
Before deploying Guacamole user resources, you will want to make sure you have a Nexus shared service deployed in the workspace so that your VMs can access package repositories through a proxy (as they can't access public repositories directly). See [Configuring shared services](./configuring-shared-services.md).
1. Navigate to the Swagger UI at `https://<azure_tre_fqdn>/api/workspaces/<workspace_id>/docs` . Where `<workspace_id>` is the workspace ID of your workspace.
1. Click `Try it out` on the `POST` `/api/workspaces/<workspace_id>/workspace-services/<service_id>/user_resources` operation. Where `<workspace_id>` and `<service_id>` are the workspace ID of your workspace and workspace service ID of your workspace service.
Expand All @@ -110,12 +113,13 @@ Once the workspace service has been created, we can use the workspace API to cre
"properties": {
"display_name": "My VM",
"description": "Will be using this VM for my research",
"os_image": "Server 2019 Data Science VM"
"os_image": "Server 2019 Data Science VM",
"nexus_version": "V2"
}
}
```
> Note: You can also specify "Windows 10" for a standard Windows 10 image
> Note: You can also specify "Windows 10" in "os_image" for a standard Windows 10 image. The "nexus_version" property also accepts "V1" if you have a V1 Nexus shared service deployed instead of the V2 service described in [Configuring shared services](./configuring-shared-services.md).
The API will return an `operation` object with a `Location` header to query the operation status, as well as the `resourceId` and `resourcePath` properties to query the resource under creation.
Expand Down
52 changes: 52 additions & 0 deletions docs/tre-developers/letsencrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Letsencrypt

Certain components of the TRE require the aquisition of a certificate via Letsencrypt to ensure secure HTTPS connections.

In order to aquire these certificates, there must be a public facing endpoint which can be reached by Letsencrypt.

As TREs are secured environments with very few publicly facing points, additional resources are required to ensure the certificate can be provisioned for the correct domain.

The additional resources are as followed:

1. Public IP provisioned in the same location as the web app that the certificate is intended for; this will also have a domain label which matches the web app name.
1. Storage Account with a static web app.
1. Application gateway to route traffic from the Public IP to the static web app

The following diagram illustrated the flow of data between the resources:

```mermaid
flowchart RL
subgraph .dev Container
direction TB
A(letsencrypt process runs)
end
subgraph External
direction TB
B[letsencrypt authority]
end
subgraph TRE
subgraph Core VNet
C[Public IP <br/> Domain Label: < web-app-name > <br/> Endpoint: < web-app-name >.< location >.cloudapp.net]
subgraph Storage Account
D[SA Static Site]
end
end
subgraph VNet
E[Key Vault <br/> kv-< tre_id >]
subgraph VM
F[Web App]
end
G[Private DNS Zone < web-app-name >.< location >.cloudapp.net]
end
end
A --> |1. Request to | B
B --> |2. Attempts to hit | C
C --> |3. App Gateway routes | D
D --> |4. Responds | C
C --> |5. Responds | B
B --> |6. Acquires certificate | A
A --> |7. Stores Certificate | E
F --> |8. Pulls Certificate | E
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ nav:
- API: 'tre-developers/api.md'
- Resource Processor: 'tre-developers/resource-processor.md'
- End to End Tests: 'tre-developers/end-to-end-tests.md'
- Letsencrypt: 'tre-developers/letsencrypt.md'
- TRE Workspace Authors:
- Authoring Workspace Templates: 'tre-workspace-authors/authoring-workspace-templates.md'
- Firewall Rules: 'tre-workspace-authors/firewall-rules.md'
Expand Down
1 change: 1 addition & 0 deletions templates/core/terraform/appgateway/staticweb.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
data "azurerm_client_config" "deployer" {}

# See https://microsoft.github.io/AzureTRE/tre-developers/letsencrypt/
resource "azurerm_storage_account" "staticweb" {
name = local.staticweb_storage_name
resource_group_name = var.resource_group_name
Expand Down
7 changes: 7 additions & 0 deletions templates/core/terraform/network/dns_zones.tf
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,10 @@ resource "azurerm_private_dns_zone" "postgres" {

lifecycle { ignore_changes = [tags] }
}

resource "azurerm_private_dns_zone" "nexus" {
name = "nexus-${var.tre_id}.${var.location}.cloudapp.azure.com"
resource_group_name = var.resource_group_name

lifecycle { ignore_changes = [tags] }
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,6 @@ resource "azurerm_key_vault_access_policy" "resource_processor" {
tenant_id = azurerm_user_assigned_identity.vmss_msi.tenant_id
object_id = azurerm_user_assigned_identity.vmss_msi.principal_id

secret_permissions = ["Get", "List", "Set", "Delete", "Purge", "Recover"]
secret_permissions = ["Get", "List", "Set", "Delete", "Purge", "Recover"]
certificate_permissions = ["Get", "Recover", "Import", "Delete", "Purge"]
}
7 changes: 7 additions & 0 deletions templates/shared_services/certs/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Put files here that you don't want copied into your bundle's invocation image
.gitignore
**/.terraform/*
**/.terraform.lock.hcl
**/*_backend.tf
Dockerfile.tmpl
2 changes: 2 additions & 0 deletions templates/shared_services/certs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.cnab/
.terraform*
26 changes: 26 additions & 0 deletions templates/shared_services/certs/Dockerfile.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM python:3.8

ARG BUNDLE_DIR

RUN apt-get update \
&& apt-get install -y ca-certificates \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

# Install Azure CLI
RUN apt-get update \
&& apt-get install -y ca-certificates jq curl apt-transport-https lsb-release gnupg \
&& curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null \
&& AZ_REPO=$(lsb_release -cs) \
&& echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | tee /etc/apt/sources.list.d/azure-cli.list \
&& apt-get update && apt-get -y install azure-cli \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

# Install Certbot
RUN apt-get update && apt-get install -y python3 python3-venv libaugeas0 \
&& python3 -m venv /opt/certbot/ \
&& /opt/certbot/bin/pip install --no-cache-dir --upgrade pip \
&& /opt/certbot/bin/pip install --no-cache-dir certbot \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

# Use the BUNDLE_DIR build argument to copy files into the bundle
COPY . $BUNDLE_DIR
38 changes: 38 additions & 0 deletions templates/shared_services/certs/parameters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"schemaVersion": "1.0.0-DRAFT",
"name": "base",
"created": "2021-06-04T13:37:29.5071039+03:00",
"modified": "2021-06-04T13:37:29.5071039+03:00",
"parameters": [
{
"name": "tre_id",
"source": {
"env": "TRE_ID"
}
},
{
"name": "azure_location",
"source": {
"env": "LOCATION"
}
},
{
"name": "tfstate_container_name",
"source": {
"env": "TERRAFORM_STATE_CONTAINER_NAME"
}
},
{
"name": "tfstate_resource_group_name",
"source": {
"env": "MGMT_RESOURCE_GROUP_NAME"
}
},
{
"name": "tfstate_storage_account_name",
"source": {
"env": "MGMT_STORAGE_ACCOUNT_NAME"
}
}
]
}
Loading

0 comments on commit 350d8a0

Please sign in to comment.