From cbada7e4a466c74b7a6282dcad49078a6433aa3b Mon Sep 17 00:00:00 2001 From: Remy Moll Date: Sat, 14 Dec 2024 16:39:27 +0100 Subject: [PATCH] move secrets to hashicorp, don't use match (wip) --- .../.github/workflows/build_app_android.yaml | 22 ++++-- frontend/.github/workflows/build_app_ios.yaml | 25 ++++--- frontend/README.md | 21 +++--- frontend/android/README.md | 8 --- frontend/ios/fastlane/Fastfile | 70 ++++++++++++++++--- frontend/ios/local.env.sample | 10 +++ 6 files changed, 115 insertions(+), 41 deletions(-) create mode 100644 frontend/ios/local.env.sample diff --git a/frontend/.github/workflows/build_app_android.yaml b/frontend/.github/workflows/build_app_android.yaml index 3769cf5..9a5c35a 100644 --- a/frontend/.github/workflows/build_app_android.yaml +++ b/frontend/.github/workflows/build_app_android.yaml @@ -39,11 +39,23 @@ jobs: # remove the 'v' prefix from the tag name echo "BUILD_NAME=${REF_NAME//v}" >> $GITHUB_ENV - - name: Load secrets from github + - name: Load secrets + id: load-secrets + uses: hashicorp/vault-action@v3 + with: + url: https://api.hashicorp.com + token: ${{ secrets.VAULT_TOKEN }} + secrets: | + secret/release GOOGLE_MAPS_API_KEY | GOOGLE_MAPS_API_KEY ; + secret/release ANDROID_SECRET_PROPERTIES_BASE64 | ANDROID_SECRET_PROPERTIES_BASE64 ; + secret/release ANDROID_GOOGLE_PLAY_JSON_BASE64 | ANDROID_GOOGLE_PLAY_JSON_BASE64 ; + secret/release ANDROID_KEYSTORE_BASE64 | ANDROID_KEYSTORE_BASE64 ; + + - name: Put selected secrets into files run: | - echo "${{ secrets.ANDROID_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties - echo "${{ secrets.ANDROID_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json - echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore + echo "${{ steps.load-secrets.outputs.ANDROID_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties + echo "${{ steps.load-secrets.outputs.ANDROID_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json + echo "${{ steps.load-secrets.outputs.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore working-directory: android - name: Install fastlane @@ -56,4 +68,4 @@ jobs: env: BUILD_NUMBER: ${{ github.run_number }} # BUILD_NAME is implicitly available - GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }} + GOOGLE_MAPS_API_KEY: ${{ steps.load-secrets.outputs.GOOGLE_MAPS_API_KEY }} diff --git a/frontend/.github/workflows/build_app_ios.yaml b/frontend/.github/workflows/build_app_ios.yaml index 544ec74..d0ac83d 100644 --- a/frontend/.github/workflows/build_app_ios.yaml +++ b/frontend/.github/workflows/build_app_ios.yaml @@ -30,12 +30,17 @@ jobs: # remove the 'v' prefix from the tag name echo "BUILD_NAME=${REF_NAME//v}" >> $GITHUB_ENV - - name: Load secrets from github - run: | - echo "${{ secrets.IOS_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties - echo "${{ secrets.IOS_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json - echo "${{ secrets.IOS_KEYSTORE_BASE64 }}" | base64 -d > release.keystore - working-directory: ios + - name: Load secrets + id: load-secrets + uses: hashicorp/vault-action@v3 + with: + url: https://api.hashicorp.com + token: ${{ secrets.VAULT_TOKEN }} + secrets: | + secret/release GOOGLE_MAPS_API_KEY | GOOGLE_MAPS_API_KEY ; + secret/release IOS_ASC_KEY_ID | IOS_ASC_KEY_ID ; + secret/release IOS_ASC_ISSUER_ID | IOS_ASC_ISSUER_ID ; + secret/release IOS_ASC_KEY_P8 | IOS_ASC_KEY_P8 ; - name: Install fastlane run: bundle install @@ -47,7 +52,7 @@ jobs: env: BUILD_NUMBER: ${{ github.run_number }} # BUILD_NAME is implicitly available - GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }} - IOS_ASC_KEY_ID: ${{ secrets.IOS_ASC_KEY_ID }} - IOS_ASC_ISSUER_ID: ${{ secrets.IOS_ASC_ISSUER_ID }} - IOS_ASC_KEY_P8: ${{ secrets.IOS_ASC_KEY_P8 }} + GOOGLE_MAPS_API_KEY: ${{ steps.load-secrets.outputs.GOOGLE_MAPS_API_KEY }} + IOS_ASC_KEY_ID: ${{ GOOGLE_MAPS_API_KEY.IOS_ASC_KEY_ID }} + IOS_ASC_ISSUER_ID: ${{ GOOGLE_MAPS_API_KEY.IOS_ASC_ISSUER_ID }} + IOS_ASC_KEY_P8: ${{ GOOGLE_MAPS_API_KEY.IOS_ASC_KEY_P8 }} diff --git a/frontend/README.md b/frontend/README.md index ea008c1..954d60d 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -46,12 +46,17 @@ bundle exec fastlane ``` This is reused in the CI/CD pipeline to automate the deployment process. -Fastlane assumes mutliple secrets to be present as files in the platform directories. These are: -- for android: - - `secrets.properties` used by gradle to load secrets needed at execution time - - `release.keystore` used by gradle to sign the apk - - `google-key.json` used by fastlane to authenticate with the Google Play Store -- for ios: - - TODO +Secrets used by fastlane are stored on hashicorp vault and are fetched by the CI/CD pipeline. See below. -These files are stored as secrets in the GitHub repository so that the CI pipeline can access them. \ No newline at end of file +## Secrets +These are mostly used by the CI/CD pipeline to deploy the application. The main usage for github actions is documented under [https://github.com/hashicorp/vault-action](https://github.com/hashicorp/vault-action). +**Global secrets** are used for both versions of the app (android and ios). +- `GOOGLE_MAPS_API_KEY` is used to authenticate with the Google Maps API + +**Platform-specific secrets** are used by the CI/CD pipeline to deploy to the respective app stores. +- `ANDROID_KEYSTORE` is used to sign the android apk +- `ANDROID_GOOGLE_KEY` is used to authenticate with the Google Play Store api +- `IOS_GOOGLE_...` +- `IOS_GOOGLE_...` +- `IOS_GOOGLE_...` +- `IOS_GOOGLE_...` \ No newline at end of file diff --git a/frontend/android/README.md b/frontend/android/README.md index 3acd427..8271562 100644 --- a/frontend/android/README.md +++ b/frontend/android/README.md @@ -63,11 +63,3 @@ Compared to the flutter template application, a few changes have to be made: } ``` - -### Using the credentials in CI -- Add the secret files to the repository secrets (e.g. `ANDROID_SECRETS_PROPERTIES`). - -- temporarily write them back to files during the CI execution: - ```bash - echo {{ secrets.ANDROID_SECRETS }} >> android/secrets.properties - ``` diff --git a/frontend/ios/fastlane/Fastfile b/frontend/ios/fastlane/Fastfile index ca7cbba..6d3d041 100644 --- a/frontend/ios/fastlane/Fastfile +++ b/frontend/ios/fastlane/Fastfile @@ -1,10 +1,7 @@ default_platform(:ios) platform :ios do - before_all do - load_asc_api_token - end - + desc "Load the App Store Connect API token" lane :load_asc_api_token do app_store_connect_api_key( @@ -16,17 +13,66 @@ platform :ios do ) end + desc "Installs signing certificate in the keychain and downloads provisioning profiles from App Store Connect" + lane :prepare_signing do |options| + team_id = CredentialsManager::AppfileConfig.try_fetch_value(:team_id) + api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY] + + keychain_name = "signing" + keychain_password = "temp" + + delete_keychain( + name: keychain_name + ) if File.exist? File.expand_path("~/Library/Keychains/#{keychain_name}-db") + + create_keychain( + name: keychain_name, + password: keychain_password, + default_keychain: true, + unlock: true, + timeout: 3600 + ) + + import_certificate( + certificate_path: ENV["SIGNING_KEY_FILE_PATH"], + certificate_password: ENV["SIGNING_KEY_PASSWORD"], + keychain_name: keychain_name, + keychain_password: keychain_password + ) + + # fetches and installs provisioning profiles from ASC + sigh( + adhoc: options[:adhoc], + api_key: api_key, + readonly: true + ) + end + + desc "Deploy a new version to closed testing (testflight)" lane :deploy_testing do build_name = ENV["BUILD_NAME"] build_number = ENV["BUILD_NUMBER"] - api_key = lane_context[SharedValues::APP_STORE_CONNECT_API_KEY] - sync_code_signing( - api_key: api_key, - type: "appstore", - readonly: true, + app_identifier = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier) + + load_asc_api_token + prepare_signing + + profile_name = "App Provisioning Profile" # replace with the name of the profile to use for the build + output_name = "example-iOS" # specify the name of the .ipa file to generate + export_method = "app-store" # specify the export method + + # turn off automatic signing during build so correct code signing identity is guaranteed to be used + update_code_signing_settings( + use_automatic_signing: false, + targets: ["main-target"], # specify which targets to update code signing settings for + code_sign_identity: "Apple Distribution", # replace with name of code signing identity if different + bundle_identifier: app_identifier, + profile_name: profile_name, + build_configurations: ["Release"] # only toggle code signing settings for Release configurations ) + sh( "flutter", @@ -40,7 +86,11 @@ platform :ios do # sign the app (whithout rebuilding it) build_app( skip_build_archive: true, - archive_path: "../build/ios/archive/Runner.xarchive" + archive_path: "../build/ios/archive/Runner.xcarchive" + provisioningProfiles: { + app_identifier => profile_name + } + ) upload_to_testflight diff --git a/frontend/ios/local.env.sample b/frontend/ios/local.env.sample new file mode 100644 index 0000000..0a5698e --- /dev/null +++ b/frontend/ios/local.env.sample @@ -0,0 +1,10 @@ +# SAMPLE env file that replicates the env in the CI/CD pipeline +# DO NOT EDIT THIS FILE +# Copy this file to local.env and edit the values to match your local environment +IOS_ASC_KEY_ID="sample" +IOS_ASC_ISSUER_ID="sample" +IOS_ASC_KEY_P8="sample" +SIGNING_KEY_FILE_PATH="sample" +SIGNING_KEY_PASSWORD="sample" +BUILD_NAME="sample" +BUILD_NUMBER="sample" \ No newline at end of file