Skip to content

Commit adbcd12

Browse files
hugosantosampagent
andauthored
auth trust-relationships: support audience, default permissions, and default token duration (#1703)
Add --audience, --grant, and --default_token_duration flags to `nsc auth trust-relationships add`, and display them in `list`. Add `-o json` output to `list`. --------- Co-authored-by: Amp <amp@ampcode.com>
1 parent 02ec57a commit adbcd12

3 files changed

Lines changed: 56 additions & 13 deletions

File tree

internal/cli/cmd/auth/trust.go

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ package auth
66

77
import (
88
"context"
9+
"encoding/json"
910
"fmt"
11+
"strings"
1012

13+
v1beta "buf.build/gen/go/namespace/cloud/protocolbuffers/go/proto/namespace/cloud/iam/v1beta"
1114
"github.com/spf13/cobra"
15+
"namespacelabs.dev/foundation/internal/cli/cmd/token"
1216
"namespacelabs.dev/foundation/internal/cli/fncobra"
1317
"namespacelabs.dev/foundation/internal/console"
1418
"namespacelabs.dev/foundation/internal/fnapi"
@@ -38,6 +42,9 @@ func newTrustAddCmd() *cobra.Command {
3842

3943
issuer := cmd.Flags().String("issuer", "", "Token issuer (required).")
4044
subjectMatch := cmd.Flags().String("subject-match", "", "Subject match pattern (required).")
45+
audience := cmd.Flags().String("audience", "", "Expected audience value.")
46+
defaultPermissions := cmd.Flags().StringArray("grant", nil, `Grant default permission as JSON object (can be specified multiple times). Format: {"resource_type":"...","resource_id":"...","actions":["..."]}`)
47+
defaultTokenDuration := cmd.Flags().String("default_token_duration", "", `Default token duration (e.g. "3600s").`)
4148

4249
return fncobra.Cmd(cmd).Do(func(ctx context.Context) error {
4350
if *issuer == "" {
@@ -48,7 +55,12 @@ func newTrustAddCmd() *cobra.Command {
4855
return fnerrors.Newf("--subject-match is required")
4956
}
5057

51-
return addTrustRelationship(ctx, *issuer, *subjectMatch)
58+
permissions, err := token.ParseGrants(*defaultPermissions)
59+
if err != nil {
60+
return err
61+
}
62+
63+
return addTrustRelationship(ctx, *issuer, *subjectMatch, *audience, permissions, *defaultTokenDuration)
5264
})
5365
}
5466

@@ -60,8 +72,10 @@ func newTrustListCmd() *cobra.Command {
6072
Args: cobra.NoArgs,
6173
}
6274

75+
output := cmd.Flags().StringP("output", "o", "", "Output format: json")
76+
6377
return fncobra.Cmd(cmd).Do(func(ctx context.Context) error {
64-
return listTrustRelationships(ctx)
78+
return listTrustRelationships(ctx, *output)
6579
})
6680
}
6781

@@ -84,8 +98,7 @@ func newTrustRemoveCmd() *cobra.Command {
8498
})
8599
}
86100

87-
func addTrustRelationship(ctx context.Context, issuer, subjectMatch string) error {
88-
// Get current trust relationships
101+
func addTrustRelationship(ctx context.Context, issuer, subjectMatch, audience string, defaultPermissions []*v1beta.Permission, defaultTokenDuration string) error {
89102
current, err := fnapi.ListTrustRelationships(ctx)
90103
if err != nil {
91104
return err
@@ -95,16 +108,16 @@ func addTrustRelationship(ctx context.Context, issuer, subjectMatch string) erro
95108
fmt.Fprintf(console.Stderr(ctx), "Issuer: %s\n", issuer)
96109
fmt.Fprintf(console.Stderr(ctx), "Subject Match: %s\n", subjectMatch)
97110

98-
// Create new trust relationship (ID and CreatorJson will be set server-side)
99111
newTrustRelationship := fnapi.StoredTrustRelationship{
100-
Issuer: issuer,
101-
SubjectMatch: subjectMatch,
112+
Issuer: issuer,
113+
SubjectMatch: subjectMatch,
114+
Audience: audience,
115+
DefaultPermissions: defaultPermissions,
116+
DefaultTokenDuration: defaultTokenDuration,
102117
}
103118

104-
// Add to existing trust relationships
105119
updatedTrustRelationships := append(current.TrustRelationships, newTrustRelationship)
106120

107-
// Update trust relationships
108121
if err := fnapi.UpdateTrustRelationships(ctx, current.Generation, updatedTrustRelationships); err != nil {
109122
return err
110123
}
@@ -113,13 +126,22 @@ func addTrustRelationship(ctx context.Context, issuer, subjectMatch string) erro
113126
return nil
114127
}
115128

116-
func listTrustRelationships(ctx context.Context) error {
129+
func listTrustRelationships(ctx context.Context, output string) error {
117130
response, err := fnapi.ListTrustRelationships(ctx)
118131
if err != nil {
119132
return err
120133
}
121134

122-
fmt.Fprintf(console.Stdout(ctx), "Trust Relationships (Generation: %s):\n\n", response.Generation)
135+
if output == "json" {
136+
bb, err := json.MarshalIndent(response.TrustRelationships, "", " ")
137+
if err != nil {
138+
return err
139+
}
140+
fmt.Fprintln(console.Stdout(ctx), string(bb))
141+
return nil
142+
}
143+
144+
fmt.Fprintf(console.Stdout(ctx), "Trust Relationships:\n\n")
123145

124146
if len(response.TrustRelationships) == 0 {
125147
fmt.Fprintf(console.Stdout(ctx), "No trust relationships configured.\n")
@@ -130,6 +152,22 @@ func listTrustRelationships(ctx context.Context) error {
130152
fmt.Fprintf(console.Stdout(ctx), "ID: %s\n", tr.Id)
131153
fmt.Fprintf(console.Stdout(ctx), " Issuer: %s\n", tr.Issuer)
132154
fmt.Fprintf(console.Stdout(ctx), " Subject Match: %s\n", tr.SubjectMatch)
155+
if tr.Audience != "" {
156+
fmt.Fprintf(console.Stdout(ctx), " Audience: %s\n", tr.Audience)
157+
}
158+
if len(tr.DefaultPermissions) > 0 {
159+
fmt.Fprintf(console.Stdout(ctx), " Default Permissions:\n")
160+
for _, p := range tr.DefaultPermissions {
161+
fmt.Fprintf(console.Stdout(ctx), " - %s: %s", p.ResourceType, strings.Join(p.Actions, ", "))
162+
if p.ResourceId != "" {
163+
fmt.Fprintf(console.Stdout(ctx), " (resource_id: %s)", p.ResourceId)
164+
}
165+
fmt.Fprintf(console.Stdout(ctx), "\n")
166+
}
167+
}
168+
if tr.DefaultTokenDuration != "" {
169+
fmt.Fprintf(console.Stdout(ctx), " Default Token Duration: %s\n", tr.DefaultTokenDuration)
170+
}
133171
if tr.CreatedAt != nil {
134172
fmt.Fprintf(console.Stdout(ctx), " Created At: %s\n", tr.CreatedAt.Format("2006-01-02 15:04:05 UTC"))
135173
}

internal/cli/cmd/token/token.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func NewCreateCmd() *cobra.Command {
130130
}
131131
defer client.Close()
132132

133-
permissions, err := parseGrants(*grants)
133+
permissions, err := ParseGrants(*grants)
134134
if err != nil {
135135
return fnerrors.BadInputError("failed to parse grants: %w", err)
136136
}
@@ -316,7 +316,7 @@ func writeTokenToFile(path string, bearerToken string) error {
316316
return os.WriteFile(path, bb, 0600)
317317
}
318318

319-
func parseGrants(grants []string) ([]*v1beta.Permission, error) {
319+
func ParseGrants(grants []string) ([]*v1beta.Permission, error) {
320320
var permissions []*v1beta.Permission
321321

322322
for _, grant := range grants {

internal/fnapi/tenants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"time"
1010

11+
v1beta "buf.build/gen/go/namespace/cloud/protocolbuffers/go/proto/namespace/cloud/iam/v1beta"
1112
"namespacelabs.dev/foundation/internal/fnerrors"
1213
)
1314

@@ -260,6 +261,10 @@ type StoredTrustRelationship struct {
260261
CreatedAt *time.Time `json:"created_at,omitempty"`
261262
Issuer string `json:"issuer,omitempty"`
262263
SubjectMatch string `json:"subject_match,omitempty"`
264+
Audience string `json:"audience,omitempty"`
265+
266+
DefaultPermissions []*v1beta.Permission `json:"default_permissions,omitempty"`
267+
DefaultTokenDuration string `json:"default_token_duration,omitempty"`
263268
}
264269

265270
type UpdateTrustRelationshipsRequest struct {

0 commit comments

Comments
 (0)