5.5 KiB
apksigner.py - An APK Signing Service
Provides code signing for APKs.
Prerequisites
The service needs an SFTP server for exchanging data with the clients.
Additionally, for signing APKs you need
- a key store file containing the certificate to sign the APKs with,
- a file containing the password to unlock the key store.
Installation
Install an Android SDK
apksigner.py needs the tools apksigner, zipalign, and apkanalyzer from
an Android SDK. The following instructions are based on the installation of
the Android SDK in KDE's Android Docker image. See below for an alternative
setup using KDE's Android Docker image.
export NDK_VERSION=22.1.7171670
export SDK_PLATFORM=android-33
export SDK_BUILD_TOOLS=30.0.3
export SDK_PACKAGES="tools platform-tools"
export ANDROID_HOME=~/android-sdk
export ANDROID_SDK_ROOT=${ANDROID_HOME}
export PATH=${ANDROID_HOME}/cmdline-tools/tools/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH}
curl -Lo /tmp/sdk-tools.zip 'https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip'
mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools
unzip -q /tmp/sdk-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools
rm -f /tmp/sdk-tools.zip
yes | sdkmanager --licenses
sdkmanager --verbose "platforms;${SDK_PLATFORM}" "build-tools;${SDK_BUILD_TOOLS}" "ndk;${NDK_VERSION}" ${SDK_PACKAGES}
sdkmanager --uninstall --verbose emulator
Install the Service
Clone this repository on a server that shall provide the service, create a virtual environment, and install the requirements.
git clone https://invent.kde.org/sysadmin/ci-notary-service.git apksigner
cd apksigner
python3 -m venv .venv
. .venv/bin/activate
pip3 install -r requirements.txt
Configure the Service
Copy apksigner.sample.ini to apksigner.ini and replace the example values
with the appropriate values for your installation.
Then copy apksigner-projects.sample.yaml to apksigner-projects.yaml and
specify the settings for the projects you want to sign APKs for.
Run the Service
Activate the virtual environment and start apksigner.py.
cd ~/apksigner
. .venv/bin/activate
python3 apksigner.py --id workerA --config apksigner.ini
where you replace workerA with a unique alpha-numeric ID for each instance
of apksigner.py you start.
Use the Service to Sign an APK
Clone this repository on the client, create a virtual environment, and install the requirements.
git clone https://invent.kde.org/sysadmin/ci-notary-service.git apksigner
cd apksigner
python3 -m venv .venv
. .venv/bin/activate
pip3 install -r requirements.txt
Copy signapk.sample.ini to signapk.ini and replace the example values
with the appropriate values for your installation. In particular, the value
for BasePath must match the corresponding value in the settings of the
service.
Then run signapk.py to sign the APK
python3 signapk.py --config signapk.ini <apk>
Managing the Service with systemd
We set up the service under the user's control with a per-user systemd instance.
Copy apksigner-user.sample.service to ~/.config/systemd/user/apksigner-user.service
and modify it as needed. The example uses the username as ID of the service
worker. Make sure that the ID is unique if you run multiple service workers.
Start the service with
systemctl --user start apksigner-user.service
If you want the service to be started automatically, then enable autostart with
systemctl --user enable apksigner-user.service
Note: By default, the systemd user instance and thus the user-managed services are started after the first login of a user and killed after the last session of the user is closed. To start the user instance right after boot, and keep the systemd user instance running after the last session closes you have to enable lingering for the user:
loginctl enable-linger USERNAME
For more details on user-managed services see https://wiki.archlinux.org/title/Systemd/User.
Running the Service with KDE's Android Docker Image
We assume that you have already created a suitable apksigner.ini and
apksigner-projects.yaml and put them in the working copy of this repository.
The correct values for apksigner.ini for KDE's Android Docker image are
[ApkSigning]
KeyStore = /keystore.jks
KeyStorePass = file:/keystorepass
SDKToolsPath = /opt/android-sdk/build-tools/30.0.2
APKAnalyzerPath = /opt/android-sdk/cmdline-tools/tools/bin/apkanalyzer
[General]
ProjectSettings = apksigner-projects.yaml
Start a Docker container from inside the working copy of this repository
passing in the working copy, the known_hosts file, the files with the KeyStore
and the password to unlock the KeyStore, and the socket of the SSH agent:
docker run -it --rm \
-v $(pwd):/apksigner \
-v <known_hosts_file>:/home/user/.ssh/known_hosts \
-v <keystorefile>:/keystore.jks -v <keystorepassfile>:/keystorepass \
-v $SSH_AUTH_SOCK:/ssh-agent --env SSH_AUTH_SOCK=/ssh-agent \
invent-registry.kde.org/sysadmin/ci-images/android-qt515
Then inside the container run:
python3 -m venv ~/.venv
. ~/.venv/bin/activate
cd /apksigner
pip3 install -r requirements.txt
python3 apksigner.py --id workerA --config apksigner.ini
Details
To protect the private SSH key we forward the SSH agent into the Docker container. Alternatively, you can mount a file holding a private OpenSSH RSA key into the container.