Skip to content

Commit

Permalink
feat: add terraform code for simple deployment,
Browse files Browse the repository at this point in the history
see terraform/README.md
  • Loading branch information
nielm committed Sep 17, 2024
1 parent 497d3e2 commit ba3773b
Show file tree
Hide file tree
Showing 21 changed files with 958 additions and 5 deletions.
20 changes: 17 additions & 3 deletions .github/workflows/codehealth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,20 @@ jobs:
node-version: 22.4.1
check-latest: true

# Install eslint
- name: Use terraform
uses: hashicorp/setup-terraform@v3

- name: Install packages
working-directory: cloudrun-malware-scanner/
run: npm install

- name: ESlint
- name: Check ESlint
working-directory: cloudrun-malware-scanner/
run: npm run eslint

- name: Check Format
working-directory: cloudrun-malware-scanner/
run: npm run check-format -- --log-level warn
run: npm run check-format

- name: Typescript checks
working-directory: cloudrun-malware-scanner/
Expand All @@ -42,3 +44,15 @@ jobs:
- name: NPM Audit
working-directory: cloudrun-malware-scanner/
run: npm audit

- name: terraform validate infra
working-directory: terraform/infra/
run: |
terraform init -no-color -input=false
terraform validate -no-color
- name: terraform validate service
working-directory: terraform/service/
run: |
terraform init -no-color -input=false
terraform validate -no-color
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ cvds
pyenv
config.json
.vscode

# Terraform
*.tfstate
*.tfstate.backup
*.tfstate.lock.info
*.tfplan
.terraform
**/.terraform/*
.terraform.tfstate.lock.info
1 change: 1 addition & 0 deletions cloudrun-malware-scanner/.gcloudignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pyenv
node_modules
.gcloudignore
.eslintrc.js
config.json.tmpl
1 change: 1 addition & 0 deletions cloudrun-malware-scanner/.husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ cd cloudrun-malware-scanner
npm run eslint
npm run check-format
npm run typecheck
npm run terraform-validate
npm audit
1 change: 1 addition & 0 deletions cloudrun-malware-scanner/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ package-lock.json
public
CHANGELOG.md
../.release-please-manifest.json
../terraform/*/.terraform
28 changes: 28 additions & 0 deletions cloudrun-malware-scanner/cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

steps:
- name: "gcr.io/cloud-builders/docker:20.10.24"
args:
[
"build",
"--tag=$LOCATION-docker.pkg.dev/$PROJECT_ID/malware-scanner/malware-scanner:latest",
"-f",
"Dockerfile",
".",
]
images:
- "$LOCATION-docker.pkg.dev/$PROJECT_ID/malware-scanner/malware-scanner:latest"
options:
logging: "CLOUD_LOGGING_ONLY"
6 changes: 5 additions & 1 deletion cloudrun-malware-scanner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
"description": "Service to scan GCS documents for the malware and move the analyzed documents to appropriate buckets",
"main": "index.js",
"scripts": {
"check-format": "prettier --config .prettierrc.js --check ..",
"check-format": "npm run prettier-check && npm run terraform-fmt-check",
"start": "node server.js",
"terraform-fmt": "terraform fmt ../terraform/*/*.tf ../terraform/*/*/*.tf",
"terraform-fmt-check": "terraform fmt -check ../terraform/*/*.tf ../terraform/*/*/*.tf",
"terraform-validate": "echo 'validating terraform/infra' && cd ../terraform/infra && terraform init -input=false && terraform validate && echo 'validating terraform/service' && cd ../service && terraform init -input=false && terraform validate",
"prettier": "prettier --config .prettierrc.js --write ..",
"prettier-check": "prettier --config .prettierrc.js --check --log-level=warn ..",
"start-proxy": "node gcs-proxy-server.js",
"test": "echo \"Error: no test specified\" && exit 1",
"eslint": "eslint *.js",
Expand Down
6 changes: 5 additions & 1 deletion release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
"bump-patch-for-minor-pre-major": false,
"draft": false,
"prerelease": false,
"include-component-in-tag": false
"include-component-in-tag": false,
"extra-files": [
"terraform/infra/versions.tf",
"terraform/service/versions.tf"
]
}
},
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
Expand Down
227 changes: 227 additions & 0 deletions terraform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# Terraform deployment

This directory contains the terraform files required to deploy the
malware-scanner service on cloud run.

The deployment is split into 4 stages:

1. Set up the google cloud project environment and service configuration.
1. Use Terraform to set up the required service accounts and deploy required
infrastructure.
1. Launch cloud build to build the Docker image for the malware-scanner
service.
1. Use Terraform to deploy the malware-scanner service to cloud run, and
connect the service to the infrastructure created in stage 2.

Follow the instructions below to use Terraform to deploy the malware scanner
service in a demo project.

## Create a project and assign billing

Using the Cloud Console, create a new Cloud project, and assign the billing
account. Take note of the Project ID of your new project.

## Clone repo

In Cloud shell, run the following to pull the malware-scanner source code from
GitHub.

```bash
git clone https://github.com/GoogleCloudPlatform/docker-clamav-malware-scanner.git
cd docker-clamav-malware-scanner
```

## Initialize environment with service configuration

Run the following commands in Cloud Shell to setup your environment and specify
the parameters of your service for the Terraform deployment.

Replace `MY_PROJECT_ID` with the ID of your newly created Project.

```bash

PROJECT_ID=MY_PROJECT_ID
gcloud config set project $PROJECT_ID

TF_VAR_project_id=$PROJECT_ID
TF_VAR_config_json=$(cat <<EOF
{
"buckets": [
{
"unscanned": "unscanned-${PROJECT_ID}",
"clean": "clean-${PROJECT_ID}",
"quarantined": "quarantined-${PROJECT_ID}"
}
],
"ClamCvdMirrorBucket": "cvd-mirror-${PROJECT_ID}"
}
EOF
)
TF_VAR_create_buckets=true
TF_VAR_region=us-central1
TF_VAR_bucket_location=us

export TF_VAR_project_id TF_VAR_region TF_VAR_bucket_location TF_VAR_config_json TF_VAR_create_buckets
```

- `TF_VAR_config_json` contains the configuration of the malware scanner (see
[config.json.tmpl](../cloudrun-malware-scanner/config.json.tmpl) for a
description of the parameters)
- `TF_VAR_create_buckets` specifies that you want Terraform to create the
unscanned/clean/quarantined buckets specified in your configuration.
- `TF_VAR_bucket_location` specifies the location of the buckets - required for
bucket creation and setting up EventArc triggers.
- `TF_VAR_region specifies` the region for the remainder of the infrastructure
the Cloud Run service, Artifact Registry, and Cloud Scheduler task.

Run the following command to enable the essential APIs for running Terraform.

```bash
gcloud services enable cloudresourcemanager.googleapis.com serviceusage.googleapis.com
```

## Set up the service accounts and deploy any infrastructure needed

Run the following commands:

```bash
cd terraform/infra
terraform init
terraform apply
```

Responding yes when prompted.

This terraform module performs the following:

- Enables require Google Cloud APIs.
- Creates an Artifact Registry repository for the malware-scanner image.
- Creates the malware-scanner and malware-scanner-build service accounts and
assigns necessary roles.
- Creates the unscanned, clean and quarantined buckets specified in the
configuration, and assigns the malware-scanner service account the admin role
on these buckets.
- Creates the bucket for the ClamAV malware definitions mirror.
- Performs an initial population of the ClamAV malware definitions mirror.

## Build the malware scanner service image

Run the following command to launch a build of the malware-scanner image using
Cloud Build

```bash
cd ../../cloudrun-malware-scanner
gcloud builds submit --region=$TF_VAR_region --config=cloudbuild.yaml \
--service-account=projects/$PROJECT_ID/serviceAccounts/malware-scanner-build@$PROJECT_ID.iam.gserviceaccount.com \
.
```

## Deploy the malware-scanner service and connect it to the infrastructure

Run the following commands:

```bash
cd ../terraform/service/
terraform init
terraform apply
```

Responding yes when prompted.

This terraform module performs the following:

- Deploys the malware-scanner service to Cloud Run using the image you built.
- Set up EventArc triggers on the configured unscanned buckets to launch a
malware scan when files are uploaded to those buckets.
- Set up a Cloud Scheduler job to periodically trigger an update of the ClamAV
malware definitions mirror.

**Note:** If the deployment fails with the following error, simply retry running
the `terraform apply -auto-approve` command

> **Error:** Error creating Trigger: googleapi: Error 400: Invalid resource
> state for "": Permission denied while using the Eventarc Service Agent. If you
> recently started to use Eventarc, it may take a few minutes before all
> necessary permissions are propagated to the Service Agent. Otherwise, verify
> that it has Eventarc Service Agent role.
## Test the service

The service can be tested by querying the version numbers from the cloud run
service, and by verifying the operation by uploading files to the unscanned GCS
bucket.

### Get version info from cloud run

You can query the malware-scanner service for the version information:

```bash
MALWARE_SCANNER_URL="$(terraform output -raw cloud_run_uri)"
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
"${MALWARE_SCANNER_URL}"
```

This command will output lines showing the versions of the malware scanner,
ClamAV and the current malware definitions version/datem for example:

```text
gcs-malware-scanner version 3.0.0
Using Clam AV version: ClamAV 1.0.5/27396/Thu Sep 12 08:46:40 2024
Service to scan GCS documents for the malware and move the analyzed documents to appropriate buckets
```

### Create and scan a clean file and an simulated infected file

Run the following command to create 2 files in the unscanned bucket, a simple
`clean.txt` file and an `eicar-infected.txt` file containing a
[test string which simulates a virus](https://en.wikipedia.org/wiki/EICAR_test_file)

```bash
echo -e 'HELLO WORLD!' \
| gcloud storage cp - "gs://unscanned-${PROJECT_ID}/clean.txt"
echo -e 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \
| gcloud storage cp - "gs://unscanned-${PROJECT_ID}/eicar-infected.txt"
```

Check contents of the unscanned bucket

```bash
gcloud storage ls gs://unscanned-${PROJECT_ID}/
```

This should return no results as the files will have been moved by the
malware-scanner. If the files still exist, re-run the command after a couple of
seconds.

Check contents of the clean files bucket

```bash
gcloud storage ls gs://clean-${PROJECT_ID}/
```

This should show that the clean.txt file has been moved to the clean bucket.

Check contents of the quarantined bucket:

```bash
gcloud storage ls gs://quarantined-${PROJECT_ID}/
```

This should show that the eicar-infected.txt file has been moved to the
quarantined bucket.

Show the log items with the scan status:

```bash
gcloud logging read \
'resource.labels.service_name = "malware-scanner" AND "Scan status for"' \
--limit=10 --format='value(jsonPayload.message)'
```

This will output log lines similar to:

```text
Scan status for gs://unscanned-PROJECT_ID/clean.txt: CLEAN (13 bytes in 85 ms)
Scan status for gs://unscanned-PROJECT_ID/eicar-infected.txt: INFECTED stream: Eicar-Signature FOUND (69 bytes in 77 ms)
```
41 changes: 41 additions & 0 deletions terraform/infra/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ba3773b

Please sign in to comment.