Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to create tokens #498

Merged
merged 43 commits into from
Aug 15, 2018
Merged

Conversation

dthomson25
Copy link
Member

Implemented Project Tokens (#472) using #228 as the overall design. In order to make it easier to add IAM authorization in the future, I created a more generic project role struct instead just creating a project token stuct. This will allow us to extend the project role to include IAMs specific roles without having to refactor the similar Jwt token work.

@dthomson25 dthomson25 requested review from alexmt and jessesuen August 7, 2018 00:25
@@ -428,7 +429,7 @@ type RepositoryList struct {
// AppProjectList is list of AppProject resources
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type AppProjectList struct {
metav1.TypeMeta `json:",inline"`
metav1.TypeMeta `json:",inline""`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extra quote is going to cause problems

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -453,6 +463,36 @@ type AppProjectSpec struct {

// Description contains optional project description
Description string `json:"description,omitempty" protobuf:"bytes,3,opt,name=description"`

Roles []ProjectRole `protobuf:"bytes,4,rep,name=roles"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs the json annotation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}

// GetRoleIndex looks up the index of a role in a project by the name
func (proj *AppProject) GetRoleIndex(name string) (int, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetRoleIndex is not very useful as an exported method on project. It's really just implementation detail. Can we make this a unexported function inside the project app server instead? Or at least someplace other than types.go, which we should try to business logic to a minimum (unless we really feel every user of the type will need it).

I might feel better about it, it it were more useful like GetRoleByName().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved GetRoleByName to a separate file in the utils folder to get it out of the types.go.

@@ -19,6 +20,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"

appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that we have to import an appclientset in the RBAC utility library, means we're not organizing the code very well. We should remove this import somehow, since this library is expected to be generic, and we have one internal project that depends on this RBAC library. In fact we eventually want to move the entire rbac library under argoproj/pkg instead of argoproj/argo-cd since we may need RBAC in other projects.

@@ -122,10 +131,47 @@ func (e *Enforcer) defaultEnforceClaims(rvals ...interface{}) bool {
}
}
user := jwtutil.GetField(mapClaims, "sub")
if strings.HasPrefix(user, "proj:") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the import issue, our custom defaultEnforceClaims can be moved to an ArgoCD specific function, which can be supplied when instantiating the enforcer using NewEnforcer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the enforcer so that if a claims enforcer function isn't provided, then we will always return false

tokenCommand.AddCommand(NewProjectDeleteTokenCommand(clientOpts))
tokenCommand.AddCommand(NewProjectAddTokenPolicyCommand(clientOpts))
tokenCommand.AddCommand(NewProjectRemoveTokenPolicyCommand(clientOpts))
command.AddCommand(tokenCommand)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our previous discussion, what users will be managing, are roles in project. And tokens will be one mechanism to authenticate to a role. IAM whitelist will be an eventual second. We need to rework the terminology on the CLI to reflect this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the cli command from token to role to address this issue.

// ProjectRoleMetatdata represents all the different types of roles a project can have
// ProjectRoleMetatdata only one of its members may be specified for a specific role
type ProjectRoleMetatdata struct {
JwtToken *JwtTokenMetadata `protobuf:"bytes,1,opt,name=jwtToken"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move JWTToken directly under ProjectRole and get rid of ProjectRoleMetatdata. After thinking about it some more, the one of property between JWT and IAM is not really necessary. We can support the mode where the same project role can be accessed by both an IAM role as well as JWT token.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, but I'm going to refactor it to allow a list of tokens as per our previous discussions

@@ -43,6 +43,12 @@ const (
badUserError = "Bad local superuser username"
)

// JwtToken the metadata of a token
type JwtToken struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This datastructure is redundant. The string returned by SessionManager.Create() is already a JWT token with information about when it was issued.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

if err != nil {
return nil, err
}
return &JwtToken{Token: token, IssuedAt: now.Unix()}, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment. IssuedAt is already being generated in the claims so we don't need a wrapper around the token string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@dthomson25 dthomson25 force-pushed the project-tokens branch 6 times, most recently from 79e4b07 to 9e317f8 Compare August 9, 2018 22:11
roleCommand.AddCommand(NewProjectRoleDeleteTokenCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleAddPolicyCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleRemovePolicyCommand(clientOpts))
command.AddCommand(roleCommand)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these roleCommand.AddCommand should be happening in the NewProjectRoleCommand() function. So then the only thing that happens here is:

command.AddCommand(NewProjectRoleCommand(clientOpts))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 fixed

@@ -351,7 +370,7 @@ message SyncOperation {
// Prune deletes resources that are no longer tracked in git
optional bool prune = 2;

// DryRun will perform a `kubectl apply --dry-run` without actually performing the sync
// DryRun will perform a `kubectl apply --dry-rudn` without actually performing the sync
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -443,6 +443,15 @@ type AppProject struct {
Spec AppProjectSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
}

//ProjectPoliciesString returns Casabin formated string of a project's polcies for each role
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casabin* typo. Also space after //

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
// Policies Stores a list of casbin formated strings that define access policies for the role in the project.
Policies []string `json:"policies" protobuf:"bytes,2,rep,name=policies"`
JWTTokens []JWTToken `json:"JWTTokens" protobuf:"bytes,3,rep,name=JWTTokens"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The golang field name should be JWTTokens. But the JSON/proto field name should be lowercase jwtTokens.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Gopkg.lock Outdated
name = "github.com/GeertJohan/go.rice"
packages = [
".",
"embedded",
"embedded"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you running older version of dep? I think you need to upgrade to dep 0.5 because otherwise we will flap between dep formats.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I was on 4.1. Let me know if the new changes from the dep ensure are a problem

fmt.Print(token.Token)
},
}
command.Flags().StringVarP(&timeBeforeExpiry, "timeBeforeExpiry", "s", "0s", "Time before the token will expire. (Default: No expiration)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets rename to expires-in per my other comment. Also "Duration" will be a better description than time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, we shouldn't use camelCase for CLI flags, preferring dashes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

timeBeforeExpiry string
)
var command = &cobra.Command{
Use: "create-token PROJECT TOKEN-NAME [--seconds seconds]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--seconds is inconsistent with the actual flag name, which I'm proposing to change to --expires-in to match the API field name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

// NewProjectRoleDeleteTokenCommand returns a new instance of an `argocd proj role delete-token` command
func NewProjectRoleDeleteTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "delete-token PROJECT ROLE-NAME ISSUED_AT",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistency between dashes and underscore with ROLE-NAME ISSUED_AT. Lets choose dashes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

fmt.Fprintf(w, "%s\n", role.Name)
if role.JWTTokens != nil {
for _, token := range role.JWTTokens {
fmt.Fprintf(w, "%s\t%d\t%d\n", role.Name, token.IssuedAt, token.ExpiresAt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a token does not expire, I think this is going to print epoch zero (1970). Instead we should print <none>

Copy link
Member

@jessesuen jessesuen Aug 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I see that it will print 0 since this is '%d'. Instead can we print the issued at and expiration time in a human readable format. e.g. 2018-08-15T12:13:14?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed this issue by breaking the list role command into a list role and a get role command. The list role command would list all the roles and their descriptions. The get role command would list the name, description, policies, and JWT tokens of a role in a project. With the JWT token, the cli lists the issue-at value as a ID to used in the delete-token and two human readable tokens for issued-at and expires-at.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example output:

./dist/argocd proj role list guestbook
ROLE-NAME                    Description
test                         desc
asdfghjklasdfghjklasdfghjkl  desc1
./dist/argocd proj role get guestbook test
Role Name: test
Description:desc
Policies:
p, proj:guestbook:test, applications, get, guestbook/guestbook-test, allow
p, proj:guestbook:test, applications, get, guestbook/*, allow
Jwt Tokens:
ID          ISSUED-AT                                  EXPIRES-AT
1534270415  Tue Aug 14 11:13:35 -0700 (4 hours ago)    <none>
1534286505  2018-08-14T15:41:45-07:00 (16 minutes ago)  2018-08-24T15:41:45-07:00 (1 week from now)
1534286515  2018-08-14T15:41:55-07:00 (16 minutes ago)  2018-09-03T15:41:55-07:00 (2 weeks from now)
1534286520  2018-08-14T15:42:00-07:00 (16 minutes ago)  2018-09-04T15:42:00-07:00 (2 weeks from now)
1534286527  2018-08-14T15:42:07-07:00 (16 minutes ago)  2018-09-05T15:42:07-07:00 (3 weeks from now)
1534286539  2018-08-14T15:42:19-07:00 (15 minutes ago)  2018-10-13T15:42:19-07:00 (1 month from now)
1534286552  2018-08-14T15:42:32-07:00 (15 minutes ago)  2018-08-14T15:43:02-07:00 (15 minutes ago)
1534286554  2018-08-14T15:42:34-07:00 (15 minutes ago)  2018-08-14T15:43:04-07:00 (15 minutes ago)
1534286558  2018-08-14T15:42:38-07:00 (15 minutes ago)  2018-08-14T15:43:08-07:00 (15 minutes ago)```

@@ -283,6 +292,16 @@ message OperationState {
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 7;
}

// ProjectRole represents a role that has access to a project
message ProjectRole {
optional string name = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I requested this earlier, but roles will need a description so that humans know the purpose of a role.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@dthomson25 dthomson25 force-pushed the project-tokens branch 3 times, most recently from 7a582b0 to f3b04fb Compare August 14, 2018 04:35
Copy link
Member

@jessesuen jessesuen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please squash and shorten the git commit message so it's not just a huge list of bullet points, before pushing.

@dthomson25 dthomson25 merged commit 66f64fb into argoproj:master Aug 15, 2018
@dthomson25 dthomson25 deleted the project-tokens branch August 15, 2018 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants