summaryrefslogtreecommitdiff
path: root/security/opkssh
diff options
context:
space:
mode:
Diffstat (limited to 'security/opkssh')
-rw-r--r--security/opkssh/Makefile50
-rw-r--r--security/opkssh/distinfo5
-rw-r--r--security/opkssh/files/patch-commands_readhome.go11
-rw-r--r--security/opkssh/files/patch-main.go91
-rw-r--r--security/opkssh/files/patch-policy_enforcer.go11
-rw-r--r--security/opkssh/files/patch-policy_policyloader.go11
-rw-r--r--security/opkssh/files/pkg-message.in22
-rw-r--r--security/opkssh/pkg-descr8
8 files changed, 209 insertions, 0 deletions
diff --git a/security/opkssh/Makefile b/security/opkssh/Makefile
new file mode 100644
index 000000000000..36c50d9ac217
--- /dev/null
+++ b/security/opkssh/Makefile
@@ -0,0 +1,50 @@
+PORTNAME= opkssh
+DISTVERSIONPREFIX= v
+DISTVERSION= 0.10.0
+CATEGORIES= security
+MASTER_SITES= LOCAL/dtxdf/${PORTNAME}/
+DISTFILES= ${PORTNAME}-${DISTVERSIONPREFIX}${DISTVERSION}.vendor${EXTRACT_SUFX}
+
+MAINTAINER= dtxdf@FreeBSD.org
+COMMENT= Tool which enables SSH to be used with OpenID Connect
+
+LICENSE= APACHE20
+LICENSE_FILE= ${WRKSRC}/LICENSE
+
+USES= go:1.23,modules
+USE_GITHUB= yes
+GH_ACCOUNT= openpubkey
+GO_BUILDFLAGS= -ldflags "-X main.Version=${DISTVERSIONPREFIX}${DISTVERSION}"
+
+SUB_FILES= pkg-message
+SUB_LIST= GROUP=${OPKSSH_GROUP} \
+ USER=${OPKSSH_USER}
+
+USERS= ${OPKSSH_USER}
+GROUPS= ${OPKSSH_GROUP}
+
+PLIST_FILES= bin/${PORTNAME}
+
+OPKSSH_USER= opksshuser
+OPKSSH_GROUP= ${OPKSSH_USER}
+
+post-extract:
+ @${MKDIR} ${WRKSRC}/vendor
+ @cd ${WRKDIR}/${PORTNAME}-vendor && ${COPYTREE_SHARE} . ${WRKSRC}/vendor
+
+# To generate the following patches:
+# - make extract
+# - cd ${WRKSRC}
+# - rg '/etc' | cut -d: -f1 | sort | uniq | grep -Ee '.+\.go$' | grep -vEe '_test\.go$' | xargs -I % cp % %.orig
+# - rg '/etc' | cut -d: -f1 | sort | uniq | grep -Ee '.+\.go$' | grep -vEe '_test\.go$' | xargs -L1 sed -i '' -Ee 's,/etc,%%PREFIX%%/etc,g'
+# - cd -
+# - make makepatch
+# - rm ${FILESDIR}/files/patch-vendor_g*
+# - Some replaced strings are just comments, so it's ok to leave them there,
+# but I'll remove them anyway to avoid unnecessary patches, so check each
+# file in FILESDIR.
+post-patch:
+ @${GREP} -Flr %%PREFIX%% ${WRKSRC} | ${XARGS} ${REINPLACE_CMD} \
+ 's,%%PREFIX%%,${PREFIX},g'
+
+.include <bsd.port.mk>
diff --git a/security/opkssh/distinfo b/security/opkssh/distinfo
new file mode 100644
index 000000000000..1569d7666eb9
--- /dev/null
+++ b/security/opkssh/distinfo
@@ -0,0 +1,5 @@
+TIMESTAMP = 1763233259
+SHA256 (opkssh-v0.10.0.vendor.tar.gz) = 038566589aa4db1bd890b20e074d0b9b995a2b766b30c72f97b35dd2afa4168e
+SIZE (opkssh-v0.10.0.vendor.tar.gz) = 5490704
+SHA256 (openpubkey-opkssh-v0.10.0_GH0.tar.gz) = 71796c060705411e98fc7d11d944c531cea1d09df14cc1331c5647a31483de41
+SIZE (openpubkey-opkssh-v0.10.0_GH0.tar.gz) = 573801
diff --git a/security/opkssh/files/patch-commands_readhome.go b/security/opkssh/files/patch-commands_readhome.go
new file mode 100644
index 000000000000..402b3d09f72e
--- /dev/null
+++ b/security/opkssh/files/patch-commands_readhome.go
@@ -0,0 +1,11 @@
+--- commands/readhome.go.orig 2025-11-15 19:19:27 UTC
++++ commands/readhome.go
+@@ -14,7 +14,7 @@
+ //
+ // SPDX-License-Identifier: Apache-2.0
+
+-//go:build linux || darwin
++//go:build linux || darwin || freebsd
+
+ package commands
+
diff --git a/security/opkssh/files/patch-main.go b/security/opkssh/files/patch-main.go
new file mode 100644
index 000000000000..9f8d47b12023
--- /dev/null
+++ b/security/opkssh/files/patch-main.go
@@ -0,0 +1,91 @@
+--- main.go.orig 2025-09-11 18:38:37 UTC
++++ main.go
+@@ -80,7 +80,7 @@ This program allows users to:
+ Short: "Appends new rule to the policy file",
+ Long: `Add appends a new policy entry in the auth_id policy file granting SSH access to the specified email or subscriber ID (sub) or group.
+
+-It first attempts to write to the system-wide file (/etc/opk/auth_id). If it lacks permissions to update this file it falls back to writing to the user-specific file (~/.opk/auth_id).
++It first attempts to write to the system-wide file (%%PREFIX%%/etc/opk/auth_id). If it lacks permissions to update this file it falls back to writing to the user-specific file (~/.opk/auth_id).
+
+ Arguments:
+ PRINCIPAL The target user account (requested principal).
+@@ -217,7 +217,7 @@ You should not call this command directly. It is calle
+ SilenceUsage: true,
+ Use: "verify <PRINCIPAL> <CERT> <KEY_TYPE>",
+ Short: "Verify an SSH key (used by sshd AuthorizedKeysCommand)",
+- Long: `Verify extracts a PK token from a base64-encoded SSH certificate and verifies it against policy. It expects an allowed provider file at /etc/opk/providers and a user policy file at either /etc/opk/auth_id or ~/.opk/auth_id.
++ Long: `Verify extracts a PK token from a base64-encoded SSH certificate and verifies it against policy. It expects an allowed provider file at %%PREFIX%%/etc/opk/providers and a user policy file at either %%PREFIX%%/etc/opk/auth_id or ~/.opk/auth_id.
+
+ This command is intended to be called by sshd as an AuthorizedKeysCommand:
+ https://man.openbsd.org/sshd_config#AuthorizedKeysCommand
+@@ -233,8 +233,8 @@ Verification checks performed:
+
+ Verification checks performed:
+ 1. Ensures the PK token is properly formed, signed, and issued by the specified OpenID Provider (OP).
+- 2. Confirms the PK token's issue (iss) and client ID (audience) are listed in the allowed provider file (/etc/opk/providers) and the token is not expired.
+- 3. Validates the identity (email or sub) in the PK token against user policies (/etc/opk/auth_id or ~/.opk/auth_id) to ensure it can assume the requested username (principal).
++ 2. Confirms the PK token's issue (iss) and client ID (audience) are listed in the allowed provider file (%%PREFIX%%/etc/opk/providers) and the token is not expired.
++ 3. Validates the identity (email or sub) in the PK token against user policies (%%PREFIX%%/etc/opk/auth_id or ~/.opk/auth_id) to ensure it can assume the requested username (principal).
+
+ If all checks pass, Verify authorizes the SSH connection.
+
+@@ -269,10 +269,10 @@ Arguments:
+ certB64Arg := args[1]
+ typArg := args[2]
+
+- providerPolicyPath := "/etc/opk/providers"
++ providerPolicyPath := "%%PREFIX%%/etc/opk/providers"
+ providerPolicy, err := policy.NewProviderFileLoader().LoadProviderPolicy(providerPolicyPath)
+ if err != nil {
+- log.Println("Failed to open /etc/opk/providers:", err)
++ log.Println("Failed to open %%PREFIX%%/etc/opk/providers:", err)
+ return err
+ }
+
+@@ -301,7 +301,7 @@ Arguments:
+ }
+ },
+ }
+- verifyCmd.Flags().StringVar(&serverConfigPathArg, "config-path", "/etc/opk/config.yml", "Path to the server config file. Default: /etc/opk/config.yml.")
++ verifyCmd.Flags().StringVar(&serverConfigPathArg, "config-path", "%%PREFIX%%/etc/opk/config.yml", "Path to the server config file. Default: %%PREFIX%%/etc/opk/config.yml.")
+ rootCmd.AddCommand(verifyCmd)
+
+ clientCmd := &cobra.Command{
+@@ -504,30 +504,30 @@ func detectOS() OSType {
+ // detectOS determines the type of operating system.
+ func detectOS() OSType {
+ // Check for RedHat-based systems
+- if _, err := os.Stat("/etc/redhat-release"); err == nil {
++ if _, err := os.Stat("%%PREFIX%%/etc/redhat-release"); err == nil {
+ return OSTypeRHEL
+ }
+
+ // Check for Debian-based systems
+- if _, err := os.Stat("/etc/debian_version"); err == nil {
++ if _, err := os.Stat("%%PREFIX%%/etc/debian_version"); err == nil {
+ return OSTypeDebian
+ }
+
+ // Check for Arch Linux
+- if _, err := os.Stat("/etc/arch-release"); err == nil {
++ if _, err := os.Stat("%%PREFIX%%/etc/arch-release"); err == nil {
+ return OSTypeArch
+ }
+
+ // Check for SUSE Linux
+- if _, err := os.Stat("/etc/SuSE-release"); err == nil {
++ if _, err := os.Stat("%%PREFIX%%/etc/SuSE-release"); err == nil {
+ return OSTypeSUSE
+ }
+- if _, err := os.Stat("/etc/SUSE-brand"); err == nil {
++ if _, err := os.Stat("%%PREFIX%%/etc/SUSE-brand"); err == nil {
+ return OSTypeSUSE
+ }
+
+- // Check for /etc/os-release which exists on most modern Linux systems
+- if content, err := os.ReadFile("/etc/os-release"); err == nil {
++ // Check for %%PREFIX%%/etc/os-release which exists on most modern Linux systems
++ if content, err := os.ReadFile("%%PREFIX%%/etc/os-release"); err == nil {
+ contentStr := string(content)
+ if strings.Contains(contentStr, "ID=rhel") ||
+ strings.Contains(contentStr, "ID=centos") ||
diff --git a/security/opkssh/files/patch-policy_enforcer.go b/security/opkssh/files/patch-policy_enforcer.go
new file mode 100644
index 000000000000..0330f82a4251
--- /dev/null
+++ b/security/opkssh/files/patch-policy_enforcer.go
@@ -0,0 +1,11 @@
+--- policy/enforcer.go.orig 2025-11-15 20:20:44 UTC
++++ policy/enforcer.go
+@@ -54,7 +54,7 @@ type checkedClaims struct {
+ }
+
+ // The default location for policy plugins
+-const pluginPolicyDir = "/etc/opk/policy.d"
++const pluginPolicyDir = "%%PREFIX%%/etc/opk/policy.d"
+
+ // Validates that the server defined identity attribute matches the
+ // respective claim from the identity token
diff --git a/security/opkssh/files/patch-policy_policyloader.go b/security/opkssh/files/patch-policy_policyloader.go
new file mode 100644
index 000000000000..e32d18134c99
--- /dev/null
+++ b/security/opkssh/files/patch-policy_policyloader.go
@@ -0,0 +1,11 @@
+--- policy/policyloader.go.orig 2025-11-15 20:20:44 UTC
++++ policy/policyloader.go
+@@ -29,7 +29,7 @@ import (
+
+ // SystemDefaultPolicyPath is the default filepath where opkssh policy is
+ // defined
+-var SystemDefaultPolicyPath = filepath.FromSlash("/etc/opk/auth_id")
++var SystemDefaultPolicyPath = filepath.FromSlash("%%PREFIX%%/etc/opk/auth_id")
+
+ // UserLookup defines the minimal interface to lookup users on the current
+ // system
diff --git a/security/opkssh/files/pkg-message.in b/security/opkssh/files/pkg-message.in
new file mode 100644
index 000000000000..49cc063a10ae
--- /dev/null
+++ b/security/opkssh/files/pkg-message.in
@@ -0,0 +1,22 @@
+[
+{ type: install
+ message: <<EOM
+Configure your sshd_config(5) with the following to use opkssh for authorization:
+
+ AuthorizedKeysCommand %%PREFIX%%/bin/opkssh verify %u %k %t
+ AuthorizedKeysCommandUser %%USER%%
+
+opkssh uses the '%%PREFIX%%/etc/opk' directory, where providers and identities are stored.
+Neither the directory nor the files are created automatically, so you must create them
+yourself. After creating the 'auth_id' and 'providers' files, they must have the
+following permissions:
+
+ chown root:%%GROUP%% %%PREFIX%%/etc/opk/auth_id
+ chmod 640 %%PREFIX%%/etc/opk/auth_id
+ chown root:%%GROUP%% %%PREFIX%%/etc/opk/providers
+ chmod 640 %%PREFIX%%/etc/opk/providers
+
+Users attempting to use opkssh from jails, please add "allow.mlock" or it will not run.
+EOM
+}
+]
diff --git a/security/opkssh/pkg-descr b/security/opkssh/pkg-descr
new file mode 100644
index 000000000000..8fa881cbe9e8
--- /dev/null
+++ b/security/opkssh/pkg-descr
@@ -0,0 +1,8 @@
+opkssh is a tool which enables ssh to be used with OpenID Connect
+allowing SSH access to be managed via identities like alice@example.com
+instead of long-lived SSH keys. It does not replace SSH, but instead
+generates SSH public keys containing PK Tokens and configures sshd
+to verify them. These PK Tokens contain standard OpenID Connect ID
+Tokens. This protocol builds on the OpenPubkey which adds user
+public keys to OpenID Connect without breaking compatibility with
+existing OpenID Provider.