Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions auth/rpcauth/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ type RPCAuthInput struct {
// Information about approvers when using multi-party authentication.
Approvers []*PrincipalAuthInput `json:"approvers"`

// TODO: commentary.
ApprovedMethodWideMpa bool `json:"approved-method-wide-mpa"`

// Information about the environment in which the policy evaluation is
// happening.
Environment *EnvironmentInput `json:"environment"`
Expand Down
13 changes: 8 additions & 5 deletions cmd/sanssh/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ import (
"context"
"flag"
"fmt"
"google.golang.org/grpc/credentials"
"io"
"os"
"path/filepath"
"time"

"google.golang.org/grpc/credentials"

"github.com/google/subcommands"
"google.golang.org/grpc"

Expand Down Expand Up @@ -78,6 +79,8 @@ type RunState struct {
BatchSize int
// If true, add an interceptor that performs the multi-party auth flow
EnableMPA bool
// If true, configure MPA interceptor to request approval method-wide.
EnableMethodWideMPA bool
// If true, the command is authz dry run and real action should not be executed
AuthzDryRun bool

Expand Down Expand Up @@ -284,8 +287,8 @@ func Run(ctx context.Context, rs RunState) {
unaryInterceptors = append(unaryInterceptors, clientAuthz.AuthorizeClient)
}
if rs.EnableMPA {
unaryInterceptors = append(unaryInterceptors, mpahooks.UnaryClientIntercepter())
streamInterceptors = append(streamInterceptors, mpahooks.StreamClientIntercepter())
unaryInterceptors = append(unaryInterceptors, mpahooks.UnaryClientIntercepter(rs.EnableMethodWideMPA))
streamInterceptors = append(streamInterceptors, mpahooks.StreamClientIntercepter(rs.EnableMethodWideMPA))
}
// timeout interceptor should be the last item in ops so that it's executed first.
streamInterceptors = append(streamInterceptors, StreamClientTimeoutInterceptor(rs.IdleTimeout))
Expand Down Expand Up @@ -366,8 +369,8 @@ func Run(ctx context.Context, rs RunState) {
conn.AuthzDryRun = rs.AuthzDryRun

if rs.EnableMPA {
conn.UnaryInterceptors = []proxy.UnaryInterceptor{mpahooks.ProxyClientUnaryInterceptor(state)}
conn.StreamInterceptors = []proxy.StreamInterceptor{mpahooks.ProxyClientStreamInterceptor(state)}
conn.UnaryInterceptors = []proxy.UnaryInterceptor{mpahooks.ProxyClientUnaryInterceptor(state, rs.EnableMethodWideMPA)}
conn.StreamInterceptors = []proxy.StreamInterceptor{mpahooks.ProxyClientStreamInterceptor(state, rs.EnableMethodWideMPA)}
}
state.Conn = conn
state.Out = output[start:end]
Expand Down
24 changes: 13 additions & 11 deletions cmd/sanssh/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ If port is blank the default of %d will be used`, proxyEnv, defaultProxyPort))
prefixHeader = flag.Bool("h", false, "If true prefix each line of output with '<index>-<target>: '")
batchSize = flag.Int("batch-size", 0, "If non-zero will perform the proxy->target work in batches of this size (with any remainder done at the end).")
mpa = flag.Bool("mpa", false, "Request multi-party approval for commands. This will create an MPA request, wait for approval, and then execute the command.")
methodWideMpa = flag.Bool("method-wide-mpa", false, "Request multi-party approval for entire method, regardless of the payload.")
authzDryRun = flag.Bool("authz-dry-run", false, "If true, the client will send a request to the server to check if the user has the permission to run the command. The server will respond with a success or failure message.")

// targets will be bound to --targets for sending a single request to N nodes.
Expand Down Expand Up @@ -200,17 +201,18 @@ func main() {
}

rs := client.RunState{
Proxy: *proxyAddr,
Targets: *targetsFlag.Target,
Outputs: *outputsFlag.Target,
AuthzDryRun: *authzDryRun,
OutputsDir: *outputsDir,
CredSource: *credSource,
IdleTimeout: *idleTimeout,
ClientAuthzPolicy: clientPolicy,
PrefixOutput: *prefixHeader,
BatchSize: *batchSize,
EnableMPA: *mpa,
Proxy: *proxyAddr,
Targets: *targetsFlag.Target,
Outputs: *outputsFlag.Target,
AuthzDryRun: *authzDryRun,
OutputsDir: *outputsDir,
CredSource: *credSource,
IdleTimeout: *idleTimeout,
ClientAuthzPolicy: clientPolicy,
PrefixOutput: *prefixHeader,
BatchSize: *batchSize,
EnableMPA: *mpa,
EnableMethodWideMPA: *methodWideMpa,
}

if *justification != "" {
Expand Down
49 changes: 37 additions & 12 deletions services/mpa/mpa.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions services/mpa/mpa.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ message Action {
string method = 3;
// The request protocol buffer.
google.protobuf.Any message = 4;
// Method-wide MPA requested, will ignore `message` and only match request on
// `method`.
bool method_wide_mpa = 5;
}

message Principal {
Expand All @@ -76,6 +79,9 @@ message StoreRequest {
string method = 1;
// The request protocol buffer.
google.protobuf.Any message = 2;
// Method-wide MPA requested, will ignore `message` and only match request on
// `method`.
bool method_wide_mpa = 5;
}

message StoreResponse {
Expand Down
2 changes: 1 addition & 1 deletion services/mpa/mpa_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading