diff options
| author | Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org> | 2025-11-16 00:23:06 +0000 |
|---|---|---|
| committer | Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org> | 2025-11-16 00:24:19 +0000 |
| commit | db1d18b39a6ad50d354a301831716c246b4c57e4 (patch) | |
| tree | aabff0f2d982543253cf614d6d86ef6c386a0041 | |
| parent | 86acb17331b0afeb5047e768181cd3f8395b173b (diff) | |
security/opkssh: New port: Tool which enables SSH to be used with OpenID Connect
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.
| -rw-r--r-- | GIDs | 2 | ||||
| -rw-r--r-- | UIDs | 2 | ||||
| -rw-r--r-- | security/Makefile | 1 | ||||
| -rw-r--r-- | security/opkssh/Makefile | 50 | ||||
| -rw-r--r-- | security/opkssh/distinfo | 5 | ||||
| -rw-r--r-- | security/opkssh/files/patch-commands_readhome.go | 11 | ||||
| -rw-r--r-- | security/opkssh/files/patch-main.go | 91 | ||||
| -rw-r--r-- | security/opkssh/files/patch-policy_enforcer.go | 11 | ||||
| -rw-r--r-- | security/opkssh/files/patch-policy_policyloader.go | 11 | ||||
| -rw-r--r-- | security/opkssh/files/pkg-message.in | 20 | ||||
| -rw-r--r-- | security/opkssh/pkg-descr | 8 |
11 files changed, 210 insertions, 2 deletions
@@ -779,7 +779,7 @@ pocket-id:*:834: filebrowser:*:835: tinyauth:*:836: homebox:*:837: -# free: 838 +opksshuser:*:838: shiori:*:839: netdisco:*:840: tcpcryptd:*:841: @@ -785,7 +785,7 @@ pocket-id:*:834:834::0:0:OIDC provider that allows users to authenticate with th filebrowser:*:835:835::0:0:Web File Browser:/var/db/filebrowser:/usr/sbin/nologin tinyauth:*:836:836::0:0:Simplest way to protect your apps with a login screen:/var/db/tinyauth:/usr/sbin/nologin homebox:*:837:837::0:0:Inventory and organization system built for the Home User:/var/db/homebox:/usr/sbin/nologin -# free: 838 +opksshuser:*:838:838::0:0:Tool which enables SSH to be used with OpenID Connect:/nonexistent:/usr/sbin/nologin shiori:*:839:839::0:0:Simple bookmark manager built with Go:/var/db/shiori:/usr/sbin/nologin netdisco:*:840:840::0:0:netdisco daemon:/usr/local/etc/netdisco:/bin/sh tcpcryptd:*:841:841::0:0:tcpcrypt daemon:/nonexistent:/usr/sbin/nologin diff --git a/security/Makefile b/security/Makefile index e6d69496ca90..e7e0723847d3 100644 --- a/security/Makefile +++ b/security/Makefile @@ -467,6 +467,7 @@ SUBDIR += openvpn-devel SUBDIR += ophcrack SUBDIR += opie + SUBDIR += opkssh SUBDIR += ossec-hids SUBDIR += ossec-hids-agent SUBDIR += ossec-hids-agent-config 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..4d0922d78ef0 --- /dev/null +++ b/security/opkssh/files/pkg-message.in @@ -0,0 +1,20 @@ +[ +{ 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 +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. |
