Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage signing keystore in Gitlab CI for android

Dear stackoverflow community, once more I turn to you :)

I've recently come across the wonder of Gitlab and their very nice bundled CI/CD solution. It works gallantly however, we all need to sign our binaries don't we and I've found no way to upload a key as I would to a Jenkins server for doing this.

So, how can I, without checking in my keys and secrets sign my android (actually flutter) application when building a release?

From what I see, most people define the build job with signing settings referring to a non-committed key.properties file specifying a local keystore.jks. This works fine when building APKs locally but if I would like to build and archive them as a part of the CI/CD job, how do I?

For secret keys, for example the passwords to the keystore itself, I've found that I can simply store them as protected variables but the actual keystore file itself. What can I do about that?

Any ideas, suggestions are dearly welcome. Cheers

Edit: I apologise for never marking a right answer here and as @IvanP proposed the solution of writing individual values to a file was what I used for a long time. But as @VonC added later, Gitlab now has the capability to data as actual files which simplifies this so I am marking that as the correct answer.

like image 837
Almund Avatar asked Aug 07 '18 11:08

Almund


3 Answers

Usually I store keystore file (as base64 string), alias and passwords to Gitlab's secrets variables.

In the .gitlab-ci.yml do something like:

create_property_files:
  stage: prepare
  only:
    - master
  script:
    - echo $KEYSTORE | base64 -d > my.keystore
    - echo "keystorePath=my.keystore" > signing.properties
    - echo "keystorePassword=$KEYSTORE_PASSWORD" >> signing.properties
    - echo "keyAlias=$ALIAS" >> signing.properties
    - echo "keyPassword=$KEY_PASSWORD" >> signing.properties
  artifacts:
    paths:
      - my.keystore
      - signing.properties
    expire_in: 10 mins

And, finally, in your build gradle:

signingConfigs {
    release {
        file("../signing.properties").with { propFile ->
            if (propFile.canRead()) {
                def properties = new Properties()
                properties.load(new FileInputStream(propFile))

                storeFile file(properties['keystorePath'])
                storePassword properties['keystorePassword']
                keyAlias properties['keyAlias']
                keyPassword properties['keyPassword']
            } else {
                println 'Unable to read signing.properties'
            }
        }
    }
}
like image 135
IvanP Avatar answered Oct 17 '22 07:10

IvanP


From IvanP's answer:

Usually I store keystore file (as base64 string), alias and passwords to Gitlab's secrets variables.

That should be easier with GitLab 15.0 (May 2022)

Project-level Secure Files in open beta

Previously, it was difficult to use binary files in your CI/CD pipelines because CI/CD variables could only contain text values. This made it difficult to make use of profiles, certificates, keystores, and other secure information, which are important for teams building mobile apps.

Today we are releasing Project-level Secure Files in open beta. Now you can upload binary files to projects in GitLab, and include those files in CI/CD jobs to be used in the build and release processes as needed. Secure Files are stored outside of version control and are not part of the project repository.

Please leave us your feedback about your experience with this feature in the feedback issue.

See Documentation and Issue.

like image 4
VonC Avatar answered Oct 17 '22 09:10

VonC


Thanks to @IvanP's answer but I had to make some changes in the Gitlab pipeline to get it working correctly.

Export the Keystore as a base64 string:

openssl base64 -A -in my.keystore > base64

Create a new variable and copy-paste the value in the file base64. Be careful while doing this, I screwed up the formatting and the pipeline was not able to decode the Keystore. The variables had to be referred to with ${} rather than just $.

- echo -n ${ANDROID_KEYSTORE} | base64 -d > my.keystore
- echo "keystorePath=../my.keystore" > myapp.properties
- echo "keystorePassword=${KEYSTORE_PASSWORD}" >> myapp.properties
- echo "keyAlias=${ALIAS_NAME}" >> myapp.properties
- echo "keyPassword=${KEY_PASSWORD}" >> myapp.properties

Refer to the myapp.properties in your build.gradle as explained above in the @IvanP's answer.

like image 4
Satheesh Avatar answered Oct 17 '22 07:10

Satheesh