javaspring-bootubuntugoogle-cloud-platforminit.d

Authenticate a local Spring Boot service with Google Cloud


I have a spring boot application that would run on a local server (not on a google cloud server). I plan to use a service account to allow the application to use Google Cloud Storage and Logging. I created a service account and an api key and downloaded the json file which looks like this:

{
  "type": "service_account",
  "project_id": "...",
  "private_key_id": "....",
  "private_key": "-----BEGIN PRIVATE KEY-----\n....\n-----END PRIVATE KEY-----\n",
  "client_email": ".....iam.gserviceaccount.com",
  "client_id": ".....",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/....."
}

If I start the app in a development environment and set an environment variable that point to the json file, the app works as expected (GOOGLE_APPLICATION_CREDENTIALS).

However, I need to run the application as an init.d service in ubuntu (the application is configured to run as an executable jar). I install my jar file as a service like this:

sudo ln -s /home/<user>/<jarname>.jar /etc/init.d/<service-name>
sudo chmod +x /etc/init.d/<service-name>
sudo update-rc.d <service-name> defaults
sudo service <service-name> start

The init.d service won't see the environment variable I set, so I need to authenticate in another way.

I installed gcloud and setup the service account like this:

gcloud auth activate-service-account service-account-name@project-name.iam.gserviceaccount.com --key-file=credentials.json
gcloud config set project <projectId>

I also ran gclout init and it shows the service account I added.

When I run the application, I get a multiple errors: com.google.api.gax.rpc.PermissionDeniedException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: The request is missing a valid API key.. Looks like something is missing, but I don't know what.

My logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/cloud/gcp/autoconfigure/logging/logback-appender.xml" />
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>

    <appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender">
        <!-- Optional : filter logs at or above a level -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <log>application.log</log> <!-- Optional : default java.log -->
        <!--resourceType>gae_app</resourceType--> <!-- Optional : default: auto-detected, fallback: global -->
        <loggingEventEnhancer>....LoggingEventEnhancer</loggingEventEnhancer>
        <flushLevel>INFO</flushLevel> <!-- Optional : default ERROR -->
    </appender>


    <root level="INFO">
        <!-- If running in GCP, remove the CONSOLE appender otherwise logs will be duplicated. -->
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="CLOUD"/>

    </root>
</configuration>

Running gcloud logging sinks list works fine on the server, so the permissions should be right.

I know about spring.cloud.gcp.credentials.location=file:/.., but it doesn't work for me. (Also, this: https://github.com/spring-cloud/spring-cloud-gcp/issues/315#issuecomment-359077878)


Solution

  • I used systemd, it allows me to set any environment variable on service start.

    1. place the executable jar and the application.properties in a folder, like /opt/<name> or /home/<user>/<name>
    2. sudo nano /etc/systemd/system/<name>.service
    3. Content:
    [Unit]
    Description=Description text...etc
    Wants=network-online.target
    After=network.target network-online.target
    
    [Service]
    Environment="LOGPATH=/var/<name>/logs"
    Environment="GOOGLE_APPLICATION_CREDENTIALS=/path-to-google-json/google/credentials.json"
    ExecStartPre=/bin/mkdir -pm 0755 ${LOGPATH}
    ExecStart=/opt/<name>/<jar-name>.jar
    PIDFile=/run/<name>/<name>%i.pid
    Restart=on-abort
    RuntimeDirectory=<name>
    RuntimeDirectoryMode=755
    WorkingDirectory=/opt/<name>
    
    [Install]
    WantedBy=multi-user.target
    
    1. Reload systemctl configs: sudo systemctl daemon-reload
    2. Set the service to start after system boot: sudo systemctl enable <name>.service
    3. Start the service with sudo systemctl start <name>.service

    Status: sudo systemctl status <name>.service

    Follow the stdout: sudo journalctl -u <name>.service --follow