# CI/CD - Secure Deployment in GCP Cloud Run / App Engine using Cloud Build and Secret Manager - Part 1

# Introduction
In this article, you will see how you can use  CI/CD pipeline using Cloud Build and Secret Manager in GCP to deploy the application in Cloud Run or App Engine. 
In Part 2 we will connect to a MySQL database using Private IP.

# STEPS
## Create a repository in GCP
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1656361461929/mQEQK-v4q.png align="left") 
Open the repository in Cloud Shell editior.

## Download a starter spring project 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1656361737913/ELDHuuUQI.png align="left")
 
Upload the demo.zip into the Cloud shell and unzip the file into the repository folder in Cloud Shell. 
## Update DemoApplication.java code

```
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;

@SpringBootApplication
@RestController
public class DemoApplication {

    @Autowired
    Environment env;
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

    @RequestMapping
    public String home(){
        return "hello gcp:" +"jdbcuser=" + env.getProperty("jdbc.user")+ " jdbcpassword=" + env.getProperty("jdbc.password")+ "jdbcurl=" + env.getProperty("jdbc.url");
    }

}
``` 

We have added environment properties in the code to check the values passed.   

## Add cloudbuild-cr.yaml in the root folder

```
steps:
  - name: gradle:7.4.2-jdk17
    entrypoint: gradle
    args: ["assemble"]
  - name: gcr.io/cloud-builders/docker
    args: ["build", "-t", "us-docker.pkg.dev/$PROJECT_ID/gcr.io/springbootgcp:$COMMIT_SHA", "--build-arg=JAR_FILE=build/libs/springbootgcp-0.0.1-SNAPSHOT.jar", "."]
  - name: gcr.io/cloud-builders/docker
    args: [ "push", "us-docker.pkg.dev/$PROJECT_ID/gcr.io/springbootgcp:$COMMIT_SHA" ]
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: ['run', 'deploy', 'springbootgcpcr', '--image',  "us-docker.pkg.dev/$PROJECT_ID/gcr.io/springbootgcp:$COMMIT_SHA" , '--allow-unauthenticated','--port=8080','--region', 'us-central1' ,'--set-secrets=--jdbc.user=jdbcuser:latest,  --jdbc.password=jdbcpassword:latest, --jdbc.url=jdbcurl:latest']
timeout: "1600s"
options:
  logging: CLOUD_LOGGING_ONLY
``` 
Cloud build runs three steps: assemble, build, push and finally run. 

## Add Dockerfile in the root folder

```
FROM openjdk:17
ARG JAR_FILE=build/libs/springbootgcp-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
    
``` 
## Add jdbc.user, jdbc.password and jdbc.url secrets in Secret Manager
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1656367007335/Clkfs2HfZ.png align="left")
Give developer and cloudbuild service account "Secret Manager Secret Accessor" role.
## Create a gcr.io Artifact repository for Docker images

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1656367427661/Q0Te469Hb.png align="left")
## Now create a Cloud Build trigger using cloudbuild-cr.yaml

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1656367523131/2ER3UdzL6.png align="left")
## Running the trigger will deploy the Cloud Run application
When you run the first time you may see an error in the build but it deploys the application properly in Cloud Run. 
## Next Step is to deploy into App Engine
## Create the app first

```
gcloud app create --region=us-central
``` 
## Add app.yaml in root folder

```
runtime: java17
entrypoint: java -jar app.jar

``` 
 ## Add cloudbuild-app.yaml in root folder

```
steps:
  - name: gcr.io/cloud-builders/gcloud
    entrypoint: 'bash'
    args: [ '-c', "gcloud secrets versions access latest --secret=appprop >  src/main/resources/application.properties" ]
  - name: gradle:7.4.2-jdk17
    entrypoint: gradle
    args: [ "assemble" ]
  - name: "gcr.io/cloud-builders/gcloud"
    entrypoint: bash
    args: ['-c', 'mkdir appdeploy && cp  /workspace/app.yaml /workspace/appdeploy/ && cp /workspace/build/libs/springbootgcp-0.0.1-SNAPSHOT.jar /workspace/appdeploy/app.jar ' ]
  - name: "gcr.io/cloud-builders/gcloud"
    entrypoint: gcloud
    args: ['app', 'deploy','./appdeploy/app.yaml' ]
timeout: "1600s"
options:
  logging: CLOUD_LOGGING_ONLY
``` 
## Add an "appprop" secret key in Secret Manager and upload a file with the following keys

```
jdbc.user=root
jdbc.password=password
jdbc.url=jdbc:mysql://10.11.0.3:3306/testdb
``` 
## Run the trigger and it would deploy the application in App Engine as a default service.

# Conclusion
I have posted a detailed [youtube video](https://youtu.be/Kl89CxiueCE) of this article. Also, the full source code is available on [GitHub](https://github.com/ssudershan/springbootgcp).
App Engine doesn't have direct integration with Secret Manager currently that's why I had to use bash script. The next step is to build on this tutorial and add a MySql connection using Private IP.



