Slide 1

Slide 1 text

@jrbowes A Token of Respect Implementing microservice identity and access management in Go

Slide 2

Slide 2 text

The evolution of access management @jrbowes

Slide 3

Slide 3 text

Single user application @jrbowes

Slide 4

Slide 4 text

@jrbowes ¯\_(ツ)_/¯

Slide 5

Slide 5 text

Single user application @jrbowes

Slide 6

Slide 6 text

Multiple users @jrbowes

Slide 7

Slide 7 text

@jrbowes Auth n Authentication

Slide 8

Slide 8 text

Multiple users @jrbowes

Slide 9

Slide 9 text

Teams @jrbowes

Slide 10

Slide 10 text

Permission levels @jrbowes

Slide 11

Slide 11 text

Authorization @jrbowes Auth z

Slide 12

Slide 12 text

Permission levels @jrbowes

Slide 13

Slide 13 text

Support users, API keys @jrbowes

Slide 14

Slide 14 text

What do we build? @jrbowes

Slide 15

Slide 15 text

Design Decisions @jrbowes

Slide 16

Slide 16 text

Selecting a model for access control @jrbowes

Slide 17

Slide 17 text

@jrbowes

Slide 18

Slide 18 text

@jrbowes ACL-MON CAPABILITY -MON POLICY-MON AD-HOC -MON

Slide 19

Slide 19 text

@jrbowes @jrbowes

Slide 20

Slide 20 text

@jrbowes @jrbowes

Slide 21

Slide 21 text

ccess Role @jrbowes ased ontrol

Slide 22

Slide 22 text

@jrbowes // Subject of role-based access control, eg a user type Subject interface { Name() string }

Slide 23

Slide 23 text

@jrbowes // Subject of role-based access control, eg a user type Subject interface { Name() string Roles() []Role } // Role provides a list of permissions type Role struct { Label string Permissions []Permission }

Slide 24

Slide 24 text

@jrbowes // Subject of role-based access control, eg a user type Subject interface { Name() string Roles() []Role } // Role provides a list of permissions type Role struct { Label string Permissions []Permission } // Permission can be many things. // type Permission struct { }

Slide 25

Slide 25 text

@jrbowes // Subject of role-based access control, eg a user type Subject interface { Name() string Roles() []Role } // Role provides a list of permissions type Role struct { Label string Permissions []Permission } // Permission can be many things. For our use we need a verb and a // target to perform that verb on. type Permission struct { Verb Verb TargetID ID }

Slide 26

Slide 26 text

NIST HQ @jrbowes INCITS 359-2004

Slide 27

Slide 27 text

Access management can be complex @jrbowes

Slide 28

Slide 28 text

Must match user expectation (detective pikachu) @jrbowes

Slide 29

Slide 29 text

The alternative is inscrutable (sonic) @jrbowes

Slide 30

Slide 30 text

Keep access management simple and well-defined for users @jrbowes

Slide 31

Slide 31 text

Monolith @jrbowes

Slide 32

Slide 32 text

Microservices @jrbowes

Slide 33

Slide 33 text

Bounded contexts @jrbowes

Slide 34

Slide 34 text

Enforcement belongs with your data @jrbowes

Slide 35

Slide 35 text

Implementation @jrbowes

Slide 36

Slide 36 text

@jrbowes IDENTITY SERVICE A SERVICE B

Slide 37

Slide 37 text

@jrbowes IDENTITY SERVICE A SERVICE B • Authenticate • Determine permission set

Slide 38

Slide 38 text

@jrbowes IDENTITY SERVICE A SERVICE B • Authenticate • Determine permission set • Authorize

Slide 39

Slide 39 text

Tokens @jrbowes

Slide 40

Slide 40 text

@jrbowes eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9. eyJleHAiOjE1NTk3NjExODQsImp0aSI6IjIxaj NjMGQzajFweHYxcTNiZGQxZXo3M2J5ZXZnIiwi c3ViIjoiMjAwMms5dXJrbjV6azNtZXgwcmFtaH pqd2VrMjAifQ. 8C6W8WatwbJNsc943GE44BX4JO_ZaIkPyHyTyl RuOyFkrOSAEKtoqH3UbWmzrQ7HpaSM6bkU_l6n 6Z0WzH1MbA eyJhbGc

Slide 41

Slide 41 text

@jrbowes header. payload payload payload payload. signature signature signature

Slide 42

Slide 42 text

(not quite) enums @jrbowes

Slide 43

Slide 43 text

@jrbowes // Verb is a action that is encapsulated in a permission, and is // requested of the RBAC system to check a if a subject is permitted // to perform an action. type Verb uint64

Slide 44

Slide 44 text

@jrbowes // Verb is a action that is encapsulated in a permission, and is // requested of the RBAC system to check a if a subject is permitted // to perform an action. type Verb uint64 // All possible permission verbs // // // // const ( TeamCreate Verb TeamRead TeamUpdate TeamInvite TeamRemove TeamDelete // ... )

Slide 45

Slide 45 text

@jrbowes // Verb is a action that is encapsulated in a permission, and is // requested of the RBAC system to check a if a subject is permitted // to perform an action. type Verb uint64 // All possible permission verbs // // // // const ( TeamCreate Verb = 1 << iota TeamRead TeamUpdate TeamInvite TeamRemove TeamDelete // ... )

Slide 46

Slide 46 text

@jrbowes // Verb is a action that is encapsulated in a permission, and is // requested of the RBAC system to check a if a subject is permitted // to perform an action. type Verb uint64 // All possible permission verbs // // // // const ( TeamCreate Verb = 1 << iota // 00...000001 TeamRead // 00...000010 TeamUpdate // 00...000100 TeamInvite // 00...001000 TeamRemove // 00...010000 TeamDelete // 00...100000 // ... )

Slide 47

Slide 47 text

@jrbowes // Verb is a action that is encapsulated in a permission, and is // requested of the RBAC system to check a if a subject is permitted // to perform an action. type Verb uint64 // 64 possible permissions // All possible permission verbs // // IMPORTANT: maintain the order in this list, or else the bits // change, and a principal's permissions could be interpreted // differently between our services. const ( TeamCreate Verb = 1 << iota // 00...000001 TeamRead // 00...000010 TeamUpdate // 00...000100 TeamInvite // 00...001000 TeamRemove // 00...010000 TeamDelete // 00...100000 // ... )

Slide 48

Slide 48 text

@jrbowes

Slide 49

Slide 49 text

@jrbowes constant 18446744073709551616 overflows Verb

Slide 50

Slide 50 text

@jrbowes // MarshalText marshals a Verb to a string, for use in JSON. Verbs are // stored in raw base64 url (no trailing ==), with leading zero bytes // removed. This allows us to both store sparse Verbs efficiently, and // have forwards compatibility as additional verbs are added, growing // the bit length. func (v Verb) MarshalText() ([]byte, error) { b := make([]byte, 8) binary.BigEndian.PutUint64(b, uint64(v)) for len(b) > 0 && b[0] == 0x00 { b = b[1:] } o := make([]byte, base64.RawURLEncoding.EncodedLen(len(b))) base64.RawURLEncoding.Encode(o, b) return o, nil }

Slide 51

Slide 51 text

@jrbowes // UnmarshalText unmarshals a string into a Verb, for use from JSON. func (v *Verb) UnmarshalText(t []byte) error { i := make([]byte, base64.RawURLEncoding.DecodedLen(len(t))) base64.RawURLEncoding.Decode(i, t) // forwards compat if len(i) > 8 { i = i[len(i)-8:] } b := make([]byte, 8) copy(b[8-len(i):], i) *v = Verb(binary.BigEndian.Uint64(b)) return nil }

Slide 52

Slide 52 text

Bit manipulation @jrbowes

Slide 53

Slide 53 text

@jrbowes func (s *JWTSubject) Can(v Verb, target ID) bool { return v&s.perms[ID] > 0 } v&s.perms[ID] return v&s.perms[ID] > 0

Slide 54

Slide 54 text

Don’t be afraid of bitwise operations @jrbowes

Slide 55

Slide 55 text

Interfaces @jrbowes

Slide 56

Slide 56 text

@jrbowes // anonymousSubject is the type representing anonymous // (not authenticated) users. It is never verified, and has // no permissions. type anonymousSubject struct{} func (anonymousSubject) Verified() bool { return false } func (anonymousSubject) Can(rbac.Verb, ...ID) bool { return false } // ... // make sure the interface is satisfied at compile time var _ Subject = anonymousSubject // anonymousSubject is the type representing anonymous // (not authenticated) users. It is never verified, and has // no permissions. type anonymousSubject struct{} func (anonymousSubject) Verified() bool { return false } func (anonymousSubject) Can(rbac.Verb, ...ID) bool { return false }

Slide 57

Slide 57 text

The future @jrbowes

Slide 58

Slide 58 text

FIND ME github.com/jbowes twitter.com/jrbowes manifold.co Thank you! @jrbowes