-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pass peer credentials from Unix domain socket to authorization engine (…
…#501) In commit 39af558, we have added the possibility of exposing a Unix domain socket to the Sansshell server. In this commit, we enhance the authentication and authorization possibilities around this new method of communication. On Linux systems, we can get information about the process which has initiated a connection over a Unix socket by means of the `getsockopt` call with the `SO_PEERCRED` option. This way, we get the UID, GID and PID of the calling process. We pass this information into the input structure of the OPA rules engine, so that rules can be written to only allow certain local users to access a particular Sansshell gRPC method, for example. An equivalent mechanism via the `getsockopt` option `LOCAL_PEERCRED`` is available on Darwin (macOS) systems, so we include Unix credentials in the auth input there as well for the sake of completeness. This also aids testability during development. In addition to the numeric UID and GID values in the credentials of a peer talking to the Sansshell server over a Unix socket, we provide the human-readable user and group names. This will enable writing more reader-friendly OPA rules based on the Unix credentials.
- Loading branch information
1 parent
65c6ba1
commit 5067420
Showing
8 changed files
with
498 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* Copyright (c) 2024 Snowflake Inc. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the | ||
"License"); you may not use this file except in compliance | ||
with the License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, | ||
software distributed under the License is distributed on an | ||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, either express or implied. See the License for the | ||
specific language governing permissions and limitations | ||
under the License. | ||
*/ | ||
|
||
package rpcauth | ||
|
||
import ( | ||
"google.golang.org/grpc/credentials" | ||
) | ||
|
||
// UnixPeerCreds represents the credentials of a Unix peer. | ||
type UnixPeerCredentials struct { | ||
Uid int | ||
Gids []int // Primary and supplementary group IDs. | ||
UserName string | ||
GroupNames []string | ||
} | ||
|
||
// UnixPeerAuthInfo contains the authentication information for a Unix peer, | ||
// in a form suitable for authentication info returned by gRPC transport credentials. | ||
type UnixPeerAuthInfo struct { | ||
credentials.CommonAuthInfo | ||
Credentials UnixPeerCredentials | ||
} | ||
|
||
func (UnixPeerAuthInfo) AuthType() string { | ||
return "insecure_with_unix_creds" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* Copyright (c) 2024 Snowflake Inc. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the | ||
"License"); you may not use this file except in compliance | ||
with the License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, | ||
software distributed under the License is distributed on an | ||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, either express or implied. See the License for the | ||
specific language governing permissions and limitations | ||
under the License. | ||
*/ | ||
|
||
package server | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
|
||
"github.com/Snowflake-Labs/sansshell/auth/opa/rpcauth" | ||
"google.golang.org/grpc/credentials" | ||
"google.golang.org/grpc/credentials/insecure" | ||
) | ||
|
||
// unixPeerTransportCredentials is a TransportCredentials implementation that fetches the | ||
// peer's credentials from the Unix domain socket. Otherwise, the channel is insecure (no TLS). | ||
type unixPeerTransportCredentials struct { | ||
insecureCredentials credentials.TransportCredentials | ||
} | ||
|
||
func (uc *unixPeerTransportCredentials) ClientHandshake(ctx context.Context, authority string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) { | ||
return uc.insecureCredentials.ClientHandshake(ctx, authority, conn) | ||
} | ||
|
||
func (uc *unixPeerTransportCredentials) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { | ||
conn, insecureAuthInfo, err := uc.insecureCredentials.ServerHandshake(conn) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
unixCreds, err := getUnixPeerCredentials(conn) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to get unix peer credentials: %w", err) | ||
} | ||
if unixCreds == nil { | ||
// This means Unix credentials are not available (not a Unix system). | ||
// We treat this connection as a basic insecure connection, with the | ||
// authentication info coming from the 'insecure' module. | ||
return conn, insecureAuthInfo, nil | ||
} | ||
|
||
unixPeerAuthInfo := rpcauth.UnixPeerAuthInfo{ | ||
CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.NoSecurity}, | ||
Credentials: *unixCreds, | ||
} | ||
return conn, unixPeerAuthInfo, nil | ||
} | ||
|
||
func (uc *unixPeerTransportCredentials) Info() credentials.ProtocolInfo { | ||
return uc.insecureCredentials.Info() | ||
} | ||
|
||
func (uc *unixPeerTransportCredentials) Clone() credentials.TransportCredentials { | ||
return &unixPeerTransportCredentials{ | ||
insecureCredentials: uc.insecureCredentials.Clone(), | ||
} | ||
} | ||
|
||
func (uc *unixPeerTransportCredentials) OverrideServerName(serverName string) error { | ||
// This is the same as the insecure implementation, but does not use | ||
// its deprecated method. | ||
return nil | ||
} | ||
|
||
// NewUnixPeerCredentials returns a new TransportCredentials that disables transport security, | ||
// but fetches the peer's credentials from the Unix domain socket. | ||
func NewUnixPeerTransportCredentials() credentials.TransportCredentials { | ||
return &unixPeerTransportCredentials{ | ||
insecureCredentials: insecure.NewCredentials(), | ||
} | ||
} |
Oops, something went wrong.