Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to use rcodesign for macosx signing service #525

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
10 changes: 5 additions & 5 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with:
java-version: '17'
distribution: 'temurin'

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@e8b34a2aaa1d35eab0b758128337086bb22bc6bf # v2.26.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -56,7 +56,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@e8b34a2aaa1d35eab0b758128337086bb22bc6bf # v2.26.5

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -70,4 +70,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@e8b34a2aaa1d35eab0b758128337086bb22bc6bf # v2.26.5
1 change: 1 addition & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ git checkout "tags/v${VERSION}" -b "v${VERSION}-branch"
./webservice/service-deployment.sh webservice/signing/jar/default.jsonnet "${VERSION}"
./webservice/service-deployment.sh webservice/signing/jar/jce.jsonnet "${VERSION}"
./webservice/service-deployment.sh webservice/signing/windows/service.jsonnet "${VERSION}"
./webservice/service-deployment.sh webservice/signing/macosx/service.jsonnet "${VERSION}"

git checkout main
git branch -d "v${VERSION}-branch"
55 changes: 55 additions & 0 deletions webservice/signing/keychain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#! /usr/bin/env bash
#*******************************************************************************
# Copyright (c) 2020 Eclipse Foundation and others.
# This program and the accompanying materials are made available
# under the terms of the Eclipse Public License 2.0
# which is available at http://www.eclipse.org/legal/epl-v20.html
# SPDX-License-Identifier: EPL-2.0
#*******************************************************************************

# Bash strict-mode
set -o errexit
set -o nounset
set -o pipefail

IFS=$'\n\t'

# Json that will be used for finding keystore metadata can either be passed to stdin or
# as the file path in $1
JSON_FILE="${1:-"/dev/stdin"}"
SERVICE_JSON=$(<"${JSON_FILE}")

KUBECTL_OPT=()
TEMP_FILES=()

for ENTRY in $(jq -r '.keystore.entries | map(tostring) | join("\n")' <<<"${SERVICE_JSON}"); do
ENTRY_NAME="$(jq -r '.name' <<<"${ENTRY}")"

echo "INFO: Processing keychain '${ENTRY_NAME}'"

KEYCHAIN_FILE="$(mktemp)"
PASSWD_FILE="$(mktemp)"

TEMP_FILES+=(${KEYCHAIN_FILE} ${PASSWD_FILE})

pass $(jq -r '.keychain.pass' <<<"${ENTRY}") >> "${KEYCHAIN_FILE}"
pass $(jq -r '.password.pass' <<<"${ENTRY}") >> "${PASSWD_FILE}"

KEYCHAIN_FILENAME=$(jq -r '.keychain.filename' <<<"${ENTRY}")
PASSWD_FILENAME=$(jq -r '.password.filename' <<<"${ENTRY}")

KUBECTL_OPT+=("--from-file=${KEYCHAIN_FILENAME}=${KEYCHAIN_FILE}")
KUBECTL_OPT+=("--from-file=${PASSWD_FILENAME}=${PASSWD_FILE}")
done

# apply keystore to the cluster
kubectl create secret generic "$(jq -r '.keystore.secretName' <<<"${SERVICE_JSON}")" \
--namespace "$(jq -r '.kube.namespace' <<<"${SERVICE_JSON}")" \
"${KUBECTL_OPT[@]}" \
--dry-run=client -o yaml | kubectl apply -f -

for TMP_FILE in "${TEMP_FILES[@]}"
do
# echo "Deleting temp file: ${TMP_FILE}"
rm -f "${TMP_FILE}"
done
49 changes: 49 additions & 0 deletions webservice/signing/macosx/create-keychain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash

# Usage:
#
# ./create-keychain.sh <certificate file> <private key file> <private key password file>
#
# Create Application keychain:
# ./create-keychain.sh developerID_application.cer private_key.p12 private_key.passwd
#
# Create Installer keychain:
# ./create-keychain.sh developerID_installer.cer private_key.p12 private_key.passwd
#
# Resulting keychain is stored in file keychain-export.p12
# Keychain password is stored in file keychain-export.passwd

DIR=$(pwd)
KEYCHAIN="${DIR}/temp.keychain"
KEYCHAIN_PASSWD="$(pwgen -s -y -1 24)"

if [ -f "${KEYCHAIN}" ];
then
echo "Deleting keychain: ${KEYCHAIN}"
rm -f "${KEYCHAIN}"
fi

echo "Creating kechain: ${KEYCHAIN}"
security create-keychain -p "${KEYCHAIN_PASSWD}" "${KEYCHAIN}"

echo "Update keychain search list"
security list-keychain -s $(security list-keychains | grep -v "${KEYCHAIN}" | xargs) "${KEYCHAIN}"
security list-keychain

CERTIFICATE=${1}
echo "Import certificate: ${CERTIFICATE}"
security import "${CERTIFICATE}" -k "${KEYCHAIN}"
PRIVATE_KEY=${2}
PRIVATE_KEY_PASSWORD=${3}
echo "Import private key: ${PRIVATE_KEY}"
security import "${PRIVATE_KEY}" -k "${KEYCHAIN}" -P "$(cat $PRIVATE_KEY_PASSWORD)"

security show-keychain-info "${KEYCHAIN}"

EXPORT="${DIR}/keychain-export.p12"
echo "Export identity to ${EXPORT}"
security export -k "${KEYCHAIN}" -t identities -f pkcs12 -o "${EXPORT}" -P "${KEYCHAIN_PASSWD}"

echo "${KEYCHAIN_PASSWD}" > "${DIR}/keychain-export.passwd"

security list-keychain -s $(security list-keychains | grep -v "${KEYCHAIN}" | xargs)
186 changes: 186 additions & 0 deletions webservice/signing/macosx/service.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
local deployment = import "../../deployment.libsonnet";

deployment.newDeployment("macosx-signing", std.extVar("artifactId"), std.extVar("version")) {
pathspec: "/macos/codesign/sign",
preDeploy: importstr "../keychain.sh",

docker+: {
registry: "ghcr.io",
repository: "eclipse-cbi",
},

keystore: {
type: "APPLE",
path: "/var/run/secrets/%s/" % $.kube.serviceName,
volumeName: "keystore",
secretName: "%s-keystore" % $.kube.serviceName,
entries: [
{
name: "Application Certificate",
keychain: {
pass: "IT/CBI/PKI/mac.developer@eclipse.org/Eclipse Foundation, Inc./application-keychain.p12",
filename: "application-keychain.p12",
},
password: {
pass: "IT/CBI/PKI/mac.developer@eclipse.org/Eclipse Foundation, Inc./application-keychain.passphrase",
filename: "application-keychain.passphrase",
},
},
{
name: "Installer Certificate",
keychain: {
pass: "IT/CBI/PKI/mac.developer@eclipse.org/Eclipse Foundation, Inc./application-keychain.p12",
filename: "installer-keychain.p12",
},
password: {
pass: "IT/CBI/PKI/mac.developer@eclipse.org/Eclipse Foundation, Inc./application-keychain.passphrase",
filename: "installer-keychain.passphrase",
},
},
],
},

kube+: {
namespace: "foundation-codesigning",
resources: [
if resource.kind == "Deployment" then resource + {
spec+: {
replicas: if std.endsWith($.version, "SNAPSHOT") then 1 else 2,
template+: {
spec+: {
containers: [
if container.name == "service" then container + {
volumeMounts+: [
{
mountPath: $.keystore.path,
name: $.keystore.volumeName,
readOnly: true
},
],
} else container for container in super.containers
],
volumes+: [
{
name: $.keystore.volumeName,
secret: {
secretName: $.keystore.secretName,
},
},
],
},
},
},
} else resource for resource in super.resources
],
},

rcodesignPath: "/usr/local/bin/rcodesign",

Dockerfile: super.Dockerfile + |||
RUN cd /usr/local/bin \
&& curl -L -o codesign.tar.gz 'https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%%2F0.27.0/apple-codesign-0.27.0-x86_64-unknown-linux-musl.tar.gz' \
&& tar xzf codesign.tar.gz --strip-components=1 \
&& rm -f codesign.tar.gz
||| % $,

configuration+: {
content: |||
##
# Optional (default = 8080)
##
server.port=%(port)s

##
# Optional
# Capture access log using log4j
##
# server.access.log=%(logFolder)s/access-yyyy_mm_dd.log

##
# Mandatory
# Must be an absolute path
##
server.temp.folder=%(tempFolder)s

##
# Mandatory
# The path that will offer the service. The version of the
# service will be appended (if server.service.pathspec.versioned
# is set to true, i.e. if you set it to /service and the current
# version is 1.3.0-SNAPSHOT, the service will be offered on
# http://server:${server.port}/service/1.3.0-SNAPSHOT
##
server.service.pathspec=%(pathspec)s

##
# Optional, boolean (default = true)
# Control whether the service version will be appended to
# server.service.pathspec
##
server.service.pathspec.versioned=false

##
# Mandatory
# The actual codesigner implementation to use
macosx.codesigner=RCODESIGNER

##
# Mandatory
macosx.rcodesign=%(rcodesignPath)s

##
# Mandatory
# The keychain containing the application certificate
macosx.identity.application.keychain=%(applicationKeychain)s

##
# Mandatory
# The password for application keychain
macosx.identity.application.keychain.password-file=%(applicationPasswordFile)s

##
# Mandatory
# The keychain containing the installer certificate
macosx.identity.installer.keychain=.%(installerKeychain)s

##
# Mandatory
# The password for installer keychain
macosx.identity.installer.keychain.password-file=%(installerPasswordFile)s

### Log4j configuration section

# Root logger option
log4j.rootLogger=INFO, console, file

# Capture jetty requests
log4j.logger.org.eclipse.jetty.server.RequestLog=INFO, console, access-log
log4j.additivity.org.eclipse.jetty.server.RequestLog=false

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%%d{yyyy-MM-dd HH:mm:ss} %%-5p %%c{1}:%%L - %%m%%n

# Redirect log messages to a log file, support file rolling.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=%(logFolder)s/server.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%%d{yyyy-MM-dd HH:mm:ss} %%-5p %%c{1}:%%L - %%m%%n

# Redirect requests to a separate access log file, support time based file rolling.
log4j.appender.access-log=org.apache.log4j.rolling.RollingFileAppender
log4j.appender.access-log.RollingPolicy = org.apache.log4j.rolling.TimeBasedRollingPolicy
log4j.appender.access-log.RollingPolicy.ActiveFileName = %(logFolder)s/access.log
log4j.appender.access-log.RollingPolicy.FileNamePattern = %(logFolder)s/access-%%d{yyyy-MM-dd}.log
log4j.appender.access-log.layout=org.apache.log4j.PatternLayout
log4j.appender.access-log.layout.ConversionPattern=%%m%%n
||| % $ {
applicationKeychain: "%s/%s" % [ $.keystore.path, $.keystore.entries[0].keychain.filename ],
applicationPasswordFile: "%s/%s" % [ $.keystore.path, $.keystore.entries[0].password.filename ],
installerKeychain: "%s/%s" % [ $.keystore.path, $.keystore.entries[1].keychain.filename ],
installerPasswordFile: "%s/%s" % [ $.keystore.path, $.keystore.entries[1].password.filename ],
},
},
}
Loading
Loading