Reputation: 1203
I have open source spring boot application and I want to deploy it to google cloud app engine with github actions CI.
My issue is, how to do this all, without hardcoding/exposing properties for production environment such as:
spring.cloud.gcp.sql.database-name
spring.cloud.gcp.sql.instance-connection-name
spring.datasource.password
spring.datasource.username
google-project-id
google cloud project service account key
My idea is to place all these values to github secrets, retrieve them in the CI, make the CI package my application with given properties and deploy it.
My problem is, can I package my application in such way that I can replace given properties inside application-prod.properties
?
My other idea was just to define environment variables for given properties and have the application retrieve them on runtime, but I am not sure if app engine supports setting environment variables.
Upvotes: 0
Views: 844
Reputation: 1203
I ended up with this solution:
I wont commit any sensitive properties to git. In CI, before deployment and packaging of the application, I write these sensitive properties with this action https://github.com/christian-draeger/write-properties , obtaining given values from GithubSecrets.
ie: step for writing database password property:
- name: set database password
uses: christian-draeger/[email protected]
with:
path: './src/main/resources/application-prod.properties'
property: 'spring.datasource.password'
value: ${{secrets.database_password}}
I like this setup, because I am setting up these properties before packaging - it's not hardcoded in the target environment.
There is one inconvenience though, with this action, it seems you can write only one property at a time, so have to repead given steps multiple times for each property.
Upvotes: 0
Reputation: 8074
I would recommend to use Secret Manager documentation to securely store environment variables in GAE:
A secret is a project-global object that contains a collection of metadata and secret versions. The metadata can include replication locations, labels, and permissions. The secret versions store the actual secret data, such as an API key or credential.
Secret Manager conceptual overview
Here you can find the java implementation:
import com.google.cloud.secretmanager.v1beta1.AccessSecretVersionRequest;
import com.google.cloud.secretmanager.v1beta1.AccessSecretVersionResponse;
import com.google.cloud.secretmanager.v1beta1.AddSecretVersionRequest;
import com.google.cloud.secretmanager.v1beta1.CreateSecretRequest;
import com.google.cloud.secretmanager.v1beta1.ProjectName;
import com.google.cloud.secretmanager.v1beta1.Replication;
import com.google.cloud.secretmanager.v1beta1.Secret;
import com.google.cloud.secretmanager.v1beta1.SecretManagerServiceClient;
import com.google.cloud.secretmanager.v1beta1.SecretPayload;
import com.google.cloud.secretmanager.v1beta1.SecretVersion;
import com.google.protobuf.ByteString;
public class Quickstart {
public void quickstart() throws Exception {
// TODO(developer): Replace these variables before running the sample.
String projectId = "your-project-id";
String secretId = "your-secret-id";
quickstart(projectId, secretId);
}
public void quickstart(String projectId, String secretId) throws Exception {
// Initialize client that will be used to send requests. This client only needs to be created
// once, and can be reused for multiple requests. After completing all of your requests, call
// the "close" method on the client to safely clean up any remaining background resources.
try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) {
// Build the parent name from the project.
ProjectName parent = ProjectName.of(projectId);
// Create the parent secret.
CreateSecretRequest createRequest =
CreateSecretRequest.newBuilder()
.setParent(parent.toString())
.setSecretId(secretId)
.setSecret(
Secret.newBuilder()
.setReplication(
Replication.newBuilder()
.setAutomatic(Replication.Automatic.newBuilder().build())
.build())
.build())
.build();
Secret secret = client.createSecret(createRequest);
// Add a secret version.
AddSecretVersionRequest addRequest =
AddSecretVersionRequest.newBuilder()
.setParent(secret.getName())
.setPayload(
SecretPayload.newBuilder()
.setData(ByteString.copyFromUtf8("hello world!"))
.build())
.build();
SecretVersion version = client.addSecretVersion(addRequest);
// Access the secret version.
AccessSecretVersionRequest accessRequest =
AccessSecretVersionRequest.newBuilder().setName(version.getName()).build();
AccessSecretVersionResponse response = client.accessSecretVersion(accessRequest);
// Print the secret payload.
//
// WARNING: Do not print the secret in a production environment - this
// snippet is showing how to access the secret material.
String payload = response.getPayload().getData().toStringUtf8();
System.out.printf("Plaintext: %s\n", payload);
}
}
}
Upvotes: 1