Where to store Android KeyStore file for CirlceCi build?
Asked Answered
W

4

19

I am trying to configure continuous integration build for my Android app. I use CircleCi platform for it. Now I store my apps Keystore.jks file locally, but CircleCi needs it to sign my app. How can I achieve that without storing the file on my git repository? Or maybe I shouldn't be concerned about that while the repository is private?

My gradle signing configs:

signingConfigs {
    if (System.getenv("CIRCLECI")) {
        release {
            keyAlias '****'
            keyPassword '****'
            storeFile file(System.getenv("******"))
            storePassword '****'
        }
    }else{
        release {
             ...
        }
    }
}

My circle.yml :

general:
    artifacts:
        - /home/ubuntu/my-app/app/build/outputs/apk/
machine:
  environment:
    ANDROID_HOME: /usr/local/android-sdk-linux
dependencies:
  override:
     - chmod +x gradlew
test:
  override:
    - ./gradlew assemble

I tried to save the keystore file on CircleCi as environmental variable but it isn't working, my build fails with exception:

> Execution failed for task ':app:validateSigningDemoRelease'.
> > Keystore file /home/ubuntu/my-app/app/  HERE_IS_THE_KEYSTORE not found for signing config 'release'.

Unsigned and debug builds finish with success.

I'm also open to use any different ci platform if you suggest something else.

Thanks in advance for every advice!

Wysocki answered 4/7, 2017 at 17:35 Comment(1)
What is your final solution for your problem?Karbala
T
43

I struggled with this problem recently and decided that the easiest solution was to encode the keystore file to base64 and put it into an environment variable at CircleCI.

This will encode the file and you can copy and paste the value across:

openssl base64 -A -in .signing/release.jks 

Then, in your config.yml file at CircleCI, decode it back:

echo $RELEASE_KEYSTORE_BASE64 | base64 -d > .signing/release.jks
Titania answered 26/4, 2018 at 11:2 Comment(4)
That's pretty smart. I'd watch out for it possibly being exposed in CI logs though. If you had an open source project for example someone could potentially open a PR and then get access to the keystore signing info. I guess the way around this is having some private CI to do the release of the app.Bairn
@Bairn for that you could use a here string instead of echo, like this: base64 -d <<< $RELEASE_KEYSTORE_BASE64 > .signing/release.jksBegone
@Titania Where should I put this echo in config.yaml? Inside the command?Perpendicular
I'm having this issue on circleci when read decoded keystore Failed to read key prophet-alias from store "/home/circleci/project/android/app/file.keystore": Short read of DER length I've tried on local and it was success, don't know whyIdealize
A
5

if statement does not work in signingConfigs. If you want to sign apk with different keystore for different flavors, you need to create signingConfigs and put signingconfigs into buildTypes section. I did some research about where to store android keystore file in CI/CD Cycle and I come up with three approaches:

  1. Encode keystore file as an environment variable

    As @grepx's answer, convert keystore file to base-64 encoded string and save it as an environment variable in CI tools.

  2. Store encrypted keystore file in version control system

    Encrypt keystore file and store it in version control system. You can encrypt file with:

    openssl aes-256-cbc -e -in keystore.jks -out keystore.jks.encrypted -k SECRET_KEY

    You need to decrypt that encrypted keystore file in build step in CI tools:

    openssl aes-256-cbc -d -in keystore.jks.encrypted -k $ENCRYPT_SECRET_KEY >> keystore.jks

    SECRET_KEY is stored as an environment variable in CI with this key: $ENCRYPT_SECRET_KEY

  3. Download keystore from external source like AWS S3, Google Drive

I've published an article about this topic in medium and you can reach complete example in github to understand better.

Adamek answered 19/11, 2018 at 18:32 Comment(0)
M
3

For me you have two solutions:

  • It's a private depot and you're the only one using it, so you can push your key.

  • My preferred solution would be to create another key that you call circleCI (for example) and that you push. Personally I use this solution

My build.gradle

signingConfigs {
        Keys {
            keyAlias 'mykey'
            storeFile file('../private_key/upload_key.jks')
            keyPassword ''
            storePassword ''
        }

        Circleci {
            keyAlias 'key'
            storeFile file('../private_key/debug_key.jks')
            keyPassword ''
            storePassword ''
        }
    }
buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
            signingConfig signingConfigs.Keys
        }
        debug {
            signingConfig signingConfigs.Keys
        }
        circleci{
            signingConfig signingConfigs.Circleci
        }
    }
Margoriemargot answered 16/8, 2017 at 9:5 Comment(0)
F
0

According to this link you have to encrypt the file like this:

openssl aes-256-cbc -a -salt -in secrets.txt -out secrets.txt.enc

and for the decryption:

    openssl aes-256-cbc -a -salt -in secrets.txt.enc -out secrets.txt.new
Fibriform answered 14/9, 2022 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.