Giter VIP home page Giter VIP logo

pam_rssh's Introduction

PAM-RSSH

Rust

This PAM module provides ssh-agent based authentication. The primary design goal is to avoid typing password when you sudo on remote servers. Instead, you can simply touch your hardware security key (e.g. Yubikey/Canokey) to fulfill user verification. The process is done by forwarding the remote authentication request to client-side ssh-agent as a signature request.

This project is developed in Rust language to minimize security flaws.

Development Status

It's ready for production use, and has been tested on production servers for over a year. More tests and feedback are welcome.

Currently supported SSH public key types:

  • RSA (with SHA256 digest)
  • DSA
  • ECDSA 256/384/521
  • ECDSA-SK (FIDO2/U2F)
  • ED25519
  • ED25519-SK (FIDO2)

Build and Install

Prerequisites:

  • OpenSSL (>=1.1.1)
  • libpam
  • Rust (with Cargo)

Clone this repo with a submodule.

git clone --recurse-submodule https://github.com/z4yx/pam_rssh.git
cd pam_rssh

Then build it using Cargo.

cargo build --release
cp target/release/libpam_rssh.so <pam module path>

pam module path

  • the module path is specific to certain distributions
OS Destination
Arch Linux /usr/lib/security/
Debian /lib/x86_64-linux-gnu/security/
openSUSE /lib/security/

Config

Add the following line to /etc/pam.d/sudo (place it before existing rules):

auth sufficient libpam_rssh.so

Then edit sudoers with visudo command. Add the following line: (It makes sudo keep the environment variable, so this module can communicate with ssh-agent)

Defaults        env_keep += "SSH_AUTH_SOCK"

Start a ssh-agent on your client, then add your keys with ssh-add.

Try to ssh to your server with forwarded agent (-A option), and make a sudo there.

Optional Arguments

The following arguments are supported:

  • loglevel=<off|error|warn|info|debug|trace> Select the level of messages logged to syslog. Defaults to warn.
  • debug Equivalent to loglevel=debug.
  • ssh_agent_addr=<IP:port or UNIX domain address> The address of ssh-agent. Defaults to the value of SSH_AUTH_SOCK environment variable, which is set by ssh automatically.
  • auth_key_file=<Path to authorized_keys> Public keys allowed for user authentication. Defaults to $HOME/.ssh/authorized_keys. Usually $HOME expands to /home/<username>.
  • authorized_keys_command=<Path to command> A command to generate the authorized_keys. It takes a single argument, the username of the user being authenticated. The standard output of this command will be parsed as authorized_keys. The auth_key_file will be ignored if you specify this argument.
  • authorized_keys_command_user=<Username> The authorized_keys_command will be run as the user specified here. If this argument is omitted, the authorized_keys_command will be run as the user being authenticated.

Arguments should be appended to the PAM rule. For example:

auth sufficient libpam_rssh.so debug authorized_keys_command=/usr/bin/sss_ssh_authorizedkeys authorized_keys_command_user=nobody

pam_rssh's People

Contributors

jamiemagee avatar smortex avatar theonandonlyzenomat avatar z4yx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pam_rssh's Issues

Error building pam_rssh

Sorry, a Rust newbie question.
I try to built pam_rssh 1.1.0 from sources for Fedora and get the following errors

warning: ambiguous glob re-exports
  --> dep/ssh-agent.rs/src/proto/mod.rs:19:9
   |
19 | pub use self::private_key::*;
   |         ^^^^^^^^^^^^^^^^^^^^ the name `MpInt` in the type namespace is first re-exported here
20 | pub use self::public_key::*;
21 | pub use self::signature::*;
   |         ------------------ but the name `MpInt` in the type namespace is also re-exported here
   |
   = note: `#[warn(ambiguous_glob_reexports)]` on by default

warning: `ssh-agent` (lib) generated 1 warning
   Compiling pam_rssh v1.1.0 (/home/dbelyavs/rpmbuild/BUILD/pam_rssh-1.1.0)
error[E0412]: cannot find type `SkSignature` in module `proto`
   --> src/sign_verify.rs:146:29
    |
146 |             let sig: proto::SkSignature = from_bytes(ssh_sig)?;
    |                             ^^^^^^^^^^^ help: a struct with a similar name exists: `Signature`
    |
   ::: /home/dbelyavs/rpmbuild/BUILD/pam_rssh-1.1.0/dep/ssh-agent.rs/src/proto/signature.rs:13:1
    |
13  | pub struct Signature {
    | -------------------- similarly named struct `Signature` defined here

error[E0599]: no variant or associated item named `SkEcDsa` found for enum `PublicKey` in the current scope
  --> src/sign_verify.rs:43:24
   |
43 |             PublicKey::SkEcDsa(input) => {
   |                        ^^^^^^^
   |                        |
   |                        variant or associated item not found in `PublicKey`
   |                        help: there is a variant with a similar name: `EcDsa`

error[E0599]: no variant or associated item named `SkEd25519` found for enum `PublicKey` in the current scope
  --> src/sign_verify.rs:54:24
   |
54 |             PublicKey::SkEd25519(input) => {
   |                        ^^^^^^^^^
   |                        |
   |                        variant or associated item not found in `PublicKey`
   |                        help: there is a variant with a similar name: `Ed25519`

error[E0599]: no variant or associated item named `SkEcDsa` found for enum `PublicKey` in the current scope
   --> src/sign_verify.rs:101:20
    |
101 |         PublicKey::SkEcDsa(_) | PublicKey::EcDsa(_) => {
    |                    ^^^^^^^
    |                    |
    |                    variant or associated item not found in `PublicKey`
    |                    help: there is a variant with a similar name: `EcDsa`

error[E0599]: no variant or associated item named `SkEcDsa` found for enum `PublicKey` in the current scope
   --> src/sign_verify.rs:145:20
    |
145 |         PublicKey::SkEcDsa(_) | PublicKey::SkEd25519(_) => {
    |                    ^^^^^^^
    |                    |
    |                    variant or associated item not found in `PublicKey`
    |                    help: there is a variant with a similar name: `EcDsa`

error[E0599]: no variant or associated item named `SkEd25519` found for enum `PublicKey` in the current scope
   --> src/sign_verify.rs:145:44
    |
145 |         PublicKey::SkEcDsa(_) | PublicKey::SkEd25519(_) => {
    |                                            ^^^^^^^^^
    |                                            |
    |                                            variant or associated item not found in `PublicKey`
    |                                            help: there is a variant with a similar name: `Ed25519`

error[E0599]: no variant or associated item named `SkEcDsa` found for enum `PublicKey` in the current scope
   --> src/sign_verify.rs:148:28
    |
148 |                 PublicKey::SkEcDsa(k) => &k.application,
    |                            ^^^^^^^
    |                            |
    |                            variant or associated item not found in `PublicKey`
    |                            help: there is a variant with a similar name: `EcDsa`

error[E0599]: no variant or associated item named `SkEd25519` found for enum `PublicKey` in the current scope
   --> src/sign_verify.rs:149:28
    |
149 |                 PublicKey::SkEd25519(k) => &k.application,
    |                            ^^^^^^^^^
    |                            |
    |                            variant or associated item not found in `PublicKey`
    |                            help: there is a variant with a similar name: `Ed25519`

Some errors have detailed explanations: E0412, E0599.
For more information about an error, try `rustc --explain E0412`.

What should I do to fix it?

Compiling errors

After compiling everything I get this error:

... = note: /usr/bin/ld: cannot find -lpam

I understand that this means ld can't find libpam.so but I don't know where to get that on Pop! OS. I'll keep looking but please let me know if you know of a solution.

Are there plans to support AuthorizedKeysCommand?

Thanks for this project, it's a nice improvement over pam_ssh_agent_auth, since it properly supports -sk keys. The one thing that seems to be missing is a form of AuthorizedKeysCommand, which makes it possible to integrate SSH with an external data source (e.g. AD/OpenLDAP/similar or a solution like privacyIdea). pam_ssh_agent_auth does support both an authorized_keys_command and authorized_keys_command_user parameter to run a command which fetches the SSH keys for a provided user. The command is run as the user in authorized_keys_command_user and is supplied with a single argument, the username, and then emits to stdout the SSH keys in authorized_keys format (see the pam_ssh_agent_auth manpage).

Needed to add `/lib/security/libpam_rssh.so`

This project works great, except that I had the error

PAM unable to dlopen(libpam_rssh.so): /lib/security/libpam_rssh.so: cannot open shared object file: No such file or directory

I was able to fix this by copying libpam_rssh.so to /lib/security/limpam_rssh.so.
I didn't find a mention of that in the README, so I am opening an issue.
If you need me to do some more tests, I am happy to do that.

Default `auth_key_file` is insecure

A process running as a given user can (in most cases) modify ~/.ssh/authorized_keys, for instance to add a new key they control before invoking whatever is using pam_rssh, subverting the authentication it is supposed to provide.

NixOS/nixpkgs#31611 provides an example (ab)using this to bypass pam_ssh_agent_auth in the context of sudo, which I believe would work similarly against pam_rssh.

Ready for distribution / production ?

Hey!

According to the README:

It's a preliminary version now. Test and feedback are needed.

Just build and installed it on my Debian machine, and it works like a charm 😍 !

Can we consider this ready for production? If so, I would suggest creating a tag so that there is an "anchor" in the project for packagers to build packages (rather than using a git tag that does not necessarily tells much). If you intend to follow semver, that might be a 1.0.0 tag meaning it can be used in production. I would then be pleased to package this for FreeBSD!

If you think that more work is required before considering this ready for production, it might still make sense to tag the code as a pre-release version. In this case, can you detail what you would like to be done and how we can help?

Thanks!

Yubikey FIDO2 ED25519-SK -- Failed to authenticate key 0: SSH-Agent reports failure

Hey @z4yx!

Super neat library, seeing some issues when trying to use the pam module, it seems to be an issue with the ssh agent, but I am struggling to track it down. For some context of the environment: SSH is established using a ECDSA-SK that has a seperate CA. I am attempting then to use the 2nd agent key that is loaded as a resident ED25519-SK key on a yubikey for sudo auth

Please let me know if I can do anything to troubleshoot here! Thanks in advance!

OS: Ubuntu 22.04 Linux sea-z1-ctu-1 5.15.0-70-generic #77-Ubuntu SMP Tue Mar 21 14:02:37 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

pam.d/sudo

#%PAM-1.0

# Set up user limits from /etc/security/limits.conf.
session    required   pam_limits.so

session    required   pam_env.so readenv=1 user_readenv=0
session    required   pam_env.so readenv=1 envfile=/etc/default/locale user_readenv=0

auth sufficient /usr/local/lib/libpam_rssh.so auth_key_file=/opt/chaos.corp/auth_sudo loglevel=trace

@include common-auth
@include common-account
@include common-session-noninteractive

auth.log

Jun  6 13:35:01 sea-z1-ctu-1 sshd[2814341]: Starting session: shell on pts/3 for max from 172.30.50.10 port 50224 id 0
Jun  6 13:35:01 sea-z1-ctu-1 sshd[2814342]: debug1: Setting controlling tty using TIOCSCTTY.
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: SSH-Agent address: /tmp/ssh-XXXXt2jJ66/agent.2814341
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Reading configured authorized_keys file: /opt/chaos.corp/auth_sudo
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: parse_authorized_keys: [email protected] AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEcmWXEXk0+TuL5BLcMmWygLYxDd8dhTbbM7yU2sI4PFAAAADHNzaDpzdWRvLXBhbQ==
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Got 1 entries from authorized_keys
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Connected to Unix("/tmp/ssh-XXXXt2jJ66/agent.2814341")
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Written 5 bytes: [00, 00, 00, 01, 0B]
Jun  6 13:37:09 sea-z1-ctu-1 sshd[2814341]: debug1: channel 2: new [accepted auth socket]
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: read_message len=725
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Read 725 bytes: [<REMOVED BYTES>]
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: list_identities: [<REMOVED BYTES>] ()
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: list_identities: [<REMOVED BYTES>] ()
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: SSH-Agent reports 1 keys
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Key 0 is authorized
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Written 131 bytes: [<REMOVED BYTES>]
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: read_message len=1
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Read 1 bytes: [05]
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: Failed to authenticate key 0: SSH-Agent reports failure
Jun  6 13:37:09 sea-z1-ctu-1 pam_rssh[2815745]: None of these keys passed authentication
Jun  6 13:37:09 sea-z1-ctu-1 sshd[2814341]: debug1: channel 2: free: accepted auth socket, nchannels 3

Fails to build

First, thank you for this. pam_ssh_agent_auth does not support ed25519-sk for use with sudo so this project looks promising.

Unfortunately, I am 100% unfamiliar with rust and cargo.

In simply cloing the repository and running cargo build --release I am presented with an error.

    Updating crates.io index
error: failed to get `pam` as a dependency of package `pam_rssh v0.2.0 (/home/dopefish/builds/pam_rssh)`

Caused by:
  failed to load source for dependency `pam`

Caused by:
  Unable to update /home/dopefish/builds/pam_rssh/dep/pam-rs/pam

Caused by:
  failed to read `/home/dopefish/builds/pam_rssh/dep/pam-rs/pam/Cargo.toml`

Caused by:
  No such file or directory (os error 2)

From here I googled pam-rs and found another github repository. In the dep folder I cloned https://github.com/anowell/pam-rs.git.

Again, I built but received another error.

    Updating crates.io index
error: failed to get `ssh-agent` as a dependency of package `pam_rssh v0.2.0 (/home/dopefish/builds/pam_rssh)`

Caused by:
  failed to load source for dependency `ssh-agent`

Caused by:
  Unable to update /home/dopefish/builds/pam_rssh/dep/ssh-agent.rs

Caused by:
  failed to read `/home/dopefish/builds/pam_rssh/dep/ssh-agent.rs/Cargo.toml`

Caused by:
  No such file or directory (os error 2)

I searched online for ssh-agent.rs and found an other github repository. Just like before I cloned https://github.com/sekey/ssh-agent.rs.git.

I went back to build again and received yet another error.

    Updating crates.io index
error: no matching package named `pam` found
location searched: /home/dopefish/builds/pam_rssh/dep/pam-rs/pam
required by package `pam_rssh v0.2.0 (/home/dopefish/builds/pam_rssh)`

There is a pam folder inside of pam-rs from the repository.

I have been unable to get past building at this point.

Help is appreciated!

Statically linked openssl

I compiled this on a system with openssl 1.1.1, but couldn't do the same for a system running openssl 3.0.
It compiles fine but ends up throwing this error in the logs:

PAM unable to dlopen(/usr/local/lib/libpam_rssh.so): libssl.so.1.1: cannot open shared object file: No such file or directory

I ended getting it to work on an openssl 3.0 system by recompiling using this method to make openssl statically linked https://docs.rs/openssl/0.10.34/openssl/#vendored

Not really sure if it's hardcoded for openssl 1.1.1 or if I messed something up to make it not work with 3.0 tbh.

two minor changes

  1. rustc 1.66 want to treat PamHandle differently, adding &mut fix that.

*** orig/lib.rs 2022-12-27 06:29:57.846782481 -0800
--- src/lib.rs 2022-12-27 06:23:00.133932449 -0800


*** 73,79 ****
}

impl PamHooks for PamRssh {
! fn sm_authenticate(pamh: &PamHandle, args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
/* if (flags & pam::constants::PAM_SILENT) == 0 */
{
setup_logger();
--- 73,79 ----
}

impl PamHooks for PamRssh {
! fn sm_authenticate(pamh: &mut PamHandle, args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
/* if (flags & pam::constants::PAM_SILENT) == 0 */
{
setup_logger();


*** 171,177 ****
}

  // Always return PAM_SUCCESS for sm_setcred, just like pam-u2f

! fn sm_setcred(_pamh: &PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
info!("set-credentials is not implemented");
PamResultCode::PAM_SUCCESS
}
--- 171,177 ----
}

  // Always return PAM_SUCCESS for sm_setcred, just like pam-u2f

! fn sm_setcred(_pamh: &mut PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
info!("set-credentials is not implemented");
PamResultCode::PAM_SUCCESS
}
2) pam-rs changed to package reference to pam-bindings, so updated Cargo.toml to use crate.io entry
pam-bindings = "^0.1.1"

the build was successful and used it in some of my machines now.

Can't use pam_rssh to auth as root without a centralized authorized_keys file

The default per user authorized_keys is hardcoded to /home/<username>/.ssh/authorized_keys. As root home dir is /root, the authorized_keys isn't found and pam_rssh auth fails:

Jun 15 15:49:25 number5 pam_rssh[20769]: read_authorized_keys: Failed to read `/home/root/.ssh/authorized_keys`

It's possible to set a centralized authorized_keys file as an workaround, but them, all users will accept the same keys, which brings another problems.

Will be nice if pam_rssh searches for authorized_keys at the user's home directory, so the we can have a per user authorized_keys not only for users that have their home dir at /home/<username>, but also in other locations, like /root.

Perform PAM item expansion on arguments

Description

PAM item expansion is a feature of some modules (source):

Some modules perform PAM item expansion on their arguments. It is a feature similar to shell’s variable expansion. During item expansion, any occurrence of $name in a string is replaced by the value of the PAM item name. If the item in question is not defined, an empty string is substituted instead.

Item information can be queried with pam_get_item (get_item in pam-bindings).

Use case

In pam_rssh, item expansion would be helpful in auth_key_file.

For instance, my system has authorized keys at /etc/ssh/authorized_keys.d/<user>. I cannot express this path using auth_key_file.

As a bonus, item expansion would allow to replace this special path logic with an actual parameter default value as is documented.

Alternatives

I tried this workaround with authorized_keys_command:

#!/usr/bin/env bash
cat "/etc/ssh/authorized_keys.d/$(whoami)"

It sort of works, but not in all situations. For example, a simple su runs the command as root, not as the requesting user. PAM provides both PAM_USER and PAM_RUSER items to differentiate the requesting user from target user.

Expose the pubkey used for authentication

Would it be possible to expose the pubkey the user was authenticated with?

I am considering writing a setgid program that authenticates the user (using PAM) before atomically modifying an authorized_keys file (in a location the user cannot otherwise write to) and it would be quite nice to check they aren't removing the key they used to authenticate (and potentially locking themselves out)

The most straightforward way to communicate that information would be through the PAM environment but pam-bindings does not seem to (currently) provide a binding for pam_setenv (and pam_getenv)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.