<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Spinnaker – Authentication &amp; Authorization</title>
    <link>https://deploy-preview-629--spinnaker-io.netlify.app/docs/reference/architecture/authz_authn/</link>
    <description>Recent content in Authentication &amp; Authorization on Spinnaker</description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="https://deploy-preview-629--spinnaker-io.netlify.app/docs/reference/architecture/authz_authn/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: Authentication Architecture</title>
      <link>https://deploy-preview-629--spinnaker-io.netlify.app/docs/reference/architecture/authz_authn/authentication/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-629--spinnaker-io.netlify.app/docs/reference/architecture/authz_authn/authentication/</guid>
      <description>
        
        
        &lt;h2 id=&#34;authentication&#34;&gt;Authentication&lt;/h2&gt;
&lt;p&gt;There are three basic players in Spinnaker&amp;rsquo;s authentication workflow:&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
graph LR
classDef default fill:#d8e8ec,stroke:#7a8288;
linkStyle default stroke:#7a8288, stroke-width:2px, fill:none;

gate(Gate)
idp(IdentityProvider)
deck(Deck/Browser)

deck--&gt;gate
gate--&gt;deck
deck--&gt;idp
idp--&gt;deck


&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deck&lt;/strong&gt;: Spinnaker&amp;rsquo;s UI. Consists of a set of static HTML, JavaScript, and CSS files. Generally
served from an Apache server, but there is nothing special about Apache that makes Deck work.
Replace with your favorite HTTP(S) server if you&amp;rsquo;d like.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gate&lt;/strong&gt;: Spinnaker&amp;rsquo;s API Gateway. All traffic (including traffic generated from Deck) flows
through Gate. It is the point at which &lt;em&gt;authentication&lt;/em&gt; is confirmed and one point (of several)
where &lt;em&gt;authorization&lt;/em&gt; is enforced.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Identity Provider&lt;/strong&gt;: This is your organization&amp;rsquo;s OAuth 2.0, SAML 2.0, or LDAP service. X.509
client certificates can be used in addition to any of these services or as a standalone identity provider.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;workflow&#34;&gt;Workflow&lt;/h3&gt;
&lt;p&gt;Deck is a Javascript Single Page Application (SPA). This means that when a user leaves the page to enter their credentials, the entire application gets loaded again when they return. As a result, the
process below involves numerous redirects between the three parties (Deck, Gate, and the
Identity Provider).&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
sequenceDiagram

    participant Apache
    participant Deck
    participant Gate
    participant IdentityProvider

    Deck-&gt;&gt;+Apache: GET deck.url
    Apache-&gt;&gt;-Deck: Returns Deck&#39;s landing page

    Deck-&gt;&gt;+Gate: GET /auth/user for user&#39;s identity
    Note right of Gate: No or expired session cookie.
    Gate-&gt;&gt;-Deck: Returns empty response


&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Browser requests Deck&amp;rsquo;s landing page: &lt;code&gt;https://deck.url:9000/&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deck checks for the user&amp;rsquo;s identity: &lt;code&gt;https://gate.url:8084/auth/user&lt;/code&gt;. Specifically, a user is
logged in if the response contains a JSON object with a non-null &amp;ldquo;username&amp;rdquo; field. &lt;code&gt;/auth/user&lt;/code&gt; is
an &lt;em&gt;unprotected&lt;/em&gt; URL but will only return the currently logged in user.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;If a user is found - all done!
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Without a user logged in, Deck requests a &lt;em&gt;protected&lt;/em&gt; URL: &lt;code&gt;https://gate.url:8084/auth/redirect?to=https://deck.url:9000&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
sequenceDiagram
participant Deck
participant Gate
participant IdentityProvider

        Deck-&gt;&gt;+Gate: GET /auth/redirect?to=deck.url
        Note right of Gate: URL is protected. Save URL in session, start login process.
        Note right of Gate: Redirect URL is auth-mechanism dependent)
        Gate-&gt;&gt;-Deck: HTTP 302 to /login

        Deck-&gt;&gt;+Gate: GET /login
        Gate-&gt;&gt;-Deck: HTTP 302 to Identity Provider

        Deck-&gt;&gt;+IdentityProvider: GET https://idp.url/?redirect_uri=gate.url/login
        IdentityProvider-&gt;&gt;-Deck: Login Page


&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Given that the URL is protected, Gate sees that there is no logged-in user, so it issues an HTTP 302
redirect to an authentication-method-specific page. It saves the requested URL
(&lt;code&gt;https://gate.url:8084/auth/redirect?to=https://deck.url:9000&lt;/code&gt;) in the session state.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
sequenceDiagram
participant Deck
participant Gate
participant IdentityProvider

        	Deck-&gt;&gt;+IdentityProvider: Login credentials
        	Note right of IdentityProvider: Success!
        	IdentityProvider-&gt;&gt;-Deck: HTTP 302 to https://gate.url/login?success

            activate Gate
        	Deck-&gt;&gt;+Gate: GET /login?success
        	Gate-&gt;&gt;+IdentityProvider: Optionally retrieve validation info
        	IdentityProvider-&gt;&gt;-Gate: .
        	deactivate Gate


&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the case of LDAP, the &lt;code&gt;/login&lt;/code&gt; page is hosted in Gate and is a basic form asking for credentials. Gate attempts to
establish a session (preferably over SSL) with the LDAP server, sending the username and password. If successful,
the session is established. Otherwise, a “Bad Credentials” exception is thrown. For SAML/OAauth methods, these
will redirect to the appropriate login page for the IDP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The user logs into the authentication provider.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The authentication provider sends a request back to Gate, usually through redirects of the user&amp;rsquo;s
browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gate processes the received data. This can include making additional requests to confirm the
user&amp;rsquo;s identity.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
sequenceDiagram
participant Deck
participant Gate
participant IdentityProvider

activate Gate
Note right of Gate: Retrieved saved URL from session.
Gate-&gt;&gt;-Deck: HTTP 302 /auth/redirect?to=deck.url

Deck-&gt;&gt;+Gate: GET /auth/redirect?to=deck.url
Note right of Gate: URL is protected, but user is authenticated. Proceed!
Gate-&gt;&gt;-Deck: HTTP 302 to deck.url

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Upon successful processing, the user is now considered logged in. Gate retrieves the originally requested URL from the session state. It issues an HTTP 302 to that URL (&lt;code&gt;https://gate.url:8084/auth/redirect?to=https://deck.url:9000&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The request from the browser hits the API gateway, along with the session cookie from the newly logged in user. The &lt;code&gt;to&lt;/code&gt; query parameter is validated to be the associated Deck instance, and a final HTTP 302 is sent, directing the user to the &lt;code&gt;https://deck.url:9000&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
    	sequenceDiagram
    	participant Apache
    	participant Deck
    	participant Gate

        Deck-&gt;&gt;+Apache: GET deck.url
        Apache-&gt;&gt;-Deck: .

        Deck-&gt;&gt;+Gate: GET /auth/user
        Note right of Gate: Valid session cookie, user is authenticated!
        Gate-&gt;&gt;-Deck: {&#39;username&#39;: &#39;foo&#39;}
        activate Deck
        Note right of Deck: User logged in! Huzzah!
        deactivate Deck

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Repeat this process from step 1. Now, the response from &lt;code&gt;https://gate.url:8084/auth/user&lt;/code&gt; will contain a proper JSON object and the rest of the application will proceed to load.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;oauth-workflow&#34;&gt;OAuth Workflow&lt;/h2&gt;
&lt;p&gt;The OAuth specification defines numerous flows for various scenarios. Spinnaker utilizes the
&lt;strong&gt;&lt;em&gt;authorization code flow&lt;/em&gt;&lt;/strong&gt;, more commonly known as the three-legged OAuth. The three-legged
OAuth
flow looks like:&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
    sequenceDiagram

    participant Deck
    participant Gate
    participant IdentityProvider
    participant ResourceServer

    Deck-&gt;&gt;+Gate: GET /something/protected
    Gate-&gt;&gt;-Deck: HTTP 302 to /login
    Deck-&gt;&gt;+Gate: GET /login
    Gate-&gt;&gt;-Deck: HTTP 302 to https://idp.url/userLogin?client_id=foo...

    Deck-&gt;&gt;+IdentityProvider: GET https://idp.url/userLogin?client_id=foo...
    IdentityProvider-&gt;&gt;-Deck: Returns login page


&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;User attempts to access a protected resource.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gate redirects to OAuth provider, passing the following important bits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;client_id&lt;/code&gt;: A pre-established identifier for this Gate instance.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redirect_uri&lt;/code&gt;: Where to send the user after login. Must be accessible by the user&amp;rsquo;s
browser.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Gate attempts to intelligently guess the &lt;code&gt;redirect_uri&lt;/code&gt; value, but outside components like
SSL terminating load balancers can cause this guess to be wrong. See

&lt;a href=&#34;https://deploy-preview-629--spinnaker-io.netlify.app/docs/setup/other_config/security/ssl/#network-configurations&#34;&gt;SSL documentation&lt;/a&gt;
 for how to fix this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;response_type=code&lt;/code&gt;: Indicating that we are performing the three-legged OAuth flow.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scope&lt;/code&gt;: What data or resources Gate would like access to. This is generally something like
&lt;code&gt;email profile&lt;/code&gt; to access the user&amp;rsquo;s email address.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OAuth provider prompts user for username &amp;amp; password.
&lt;div class=&#34;mermaid&#34;&gt;
  
        sequenceDiagram

        participant Deck
        participant Gate
        participant IdentityProvider
        participant ResourceServer

        Deck-&gt;&gt;+IdentityProvider: User sends credentials
        IdentityProvider-&gt;&gt;-Deck: Confirms client_id &#39;foo&#39; can access user&#39;s information
        Deck-&gt;&gt;+IdentityProvider: User confirms
        IdentityProvider-&gt;&gt;-Deck: HTTP 302 to https://gate.url/login?code=abcdef


&lt;/div&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OAuth provider confirms that the user is granting Gate access to their profile.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using the &lt;code&gt;redirect_uri&lt;/code&gt;, the OAuth provider redirects the user to this address, providing an
additional &lt;code&gt;code&lt;/code&gt; parameter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;mermaid&#34;&gt;
  
            sequenceDiagram

            participant Deck
            participant Gate
            participant IdentityProvider
            participant ResourceServer

            Deck-&gt;&gt;+Gate: GET /login?code=abcdef
            Gate-&gt;&gt;+IdentityProvider: POST /token &#34;{code:abcdef, client_id:..., client_secret:...}&#34;
            IdentityProvider-&gt;&gt;-Gate: Responds with access token `12345`
            Gate-&gt;&gt;+ResourceServer: GET /userInfo with &#34;Authorization: Bearer 12345&#34; header
            ResourceServer-&gt;&gt;-Gate: Respondes with JSON of user profile information
            Note left of Gate: Gate extracts data based on userInfoMapping
            Gate-&gt;&gt;-Deck: HTTP 302 to originally requested URL

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Gate uses this &lt;code&gt;code&lt;/code&gt; parameter to request an &lt;em&gt;access token&lt;/em&gt; from the OAuth provider&amp;rsquo;s token
server.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gate uses the &lt;em&gt;access token&lt;/em&gt; to request user profile data from the resource server
(&lt;code&gt;security.oauth2.resource.userInfoUri&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gate uses the &lt;code&gt;userInfoMapping&lt;/code&gt; to extract specific fields from the response, such as the
username and email address, and associates it with the established session cookie with the user.
See UserInfoMapping below.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The authorization code flow is the most secure way to get this data, because the &lt;em&gt;access token&lt;/em&gt;
is never revealed outside of the server using it.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Authorization Architecture</title>
      <link>https://deploy-preview-629--spinnaker-io.netlify.app/docs/reference/architecture/authz_authn/authorization/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-629--spinnaker-io.netlify.app/docs/reference/architecture/authz_authn/authorization/</guid>
      <description>
        
        
        &lt;h2 id=&#34;ingress&#34;&gt;Ingress&lt;/h2&gt;
&lt;p&gt;Ingress involves the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clouddriver.&lt;/li&gt;
&lt;li&gt;Front50 to query apps and service accounts.&lt;/li&gt;
&lt;li&gt;Gate signs users in with externally provided roles (e.g. OpenID Connect, SAML). These roles are then merged with provider sourced roles (if any), tagged with the &lt;code&gt;EXTERNAL&lt;/code&gt; source, and cached in Redis.&lt;/li&gt;
&lt;li&gt;Igor gets the list of build systems and roles required to access them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;egress&#34;&gt;Egress&lt;/h2&gt;
&lt;p&gt;Egress involves the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redis stores computed roles, default permissions, and roles from external systems.&lt;/li&gt;
&lt;li&gt;Clouddriver gets known accounts.&lt;/li&gt;
&lt;li&gt;Front50 gets known apps.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;scaling&#34;&gt;Scaling&lt;/h2&gt;
&lt;p&gt;Fiat can be scaled by adding replicas. &lt;code&gt;fiat.writeMode.enabled&lt;/code&gt; dictates if the Fiat instance will try to sync
roles. Fiat instances coordinate around locks (in Redis) to ensure that only one instance synchronizes roles at a time.&lt;/p&gt;
&lt;h2 id=&#34;implementation-details&#34;&gt;Implementation Details&lt;/h2&gt;
&lt;h3 id=&#34;roles-and-permissions&#34;&gt;Roles and Permissions&lt;/h3&gt;
&lt;p&gt;Fiat uses the following model for user permissions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a user ID (= a real one or 
&lt;a href=&#34;#unrestricted-user&#34;&gt;&amp;lt;code&amp;gt;__unrestricted_user__&amp;lt;/code&amp;gt;&lt;/a&gt;
  )&lt;/li&gt;
&lt;li&gt;Accounts permission = list of { name + cloudProvider + Permissions)&lt;/li&gt;
&lt;li&gt;Apps permissions = list of { name + permissions }&lt;/li&gt;
&lt;li&gt;Service accounts = list of service accounts the user belongs to&lt;/li&gt;
&lt;li&gt;Roles: list of roles the user has&lt;/li&gt;
&lt;li&gt;build services: list of build services the user has access to&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sync&#34;&gt;Sync&lt;/h3&gt;
&lt;p&gt;Every 30 seconds, Fiat checks if it needs to sync roles. Every 10 minutes (by default), it will sync user ↔ roles. It may mean querying the provider for all the roles of all the users that Fiat knows about (= are cached in Redis).&lt;/p&gt;
&lt;h4 id=&#34;unrestricted-user&#34;&gt;Unrestricted User&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;At any point, the unrestricted virtual user should have &lt;code&gt;UserPermission&lt;/code&gt; in the permission repository (Redis for now) for all accounts, apps, service accounts, build services that have not been restricted (no permission specified).&lt;/li&gt;
&lt;li&gt;The unrestricted user’s permissions is updated on every sync to account for permission changes and for new apps, accounts, etc.&lt;/li&gt;
&lt;li&gt;When returning a user’s permission is returned, it is merged with the unrestricted user. By having the account, app, service account, build service in the &lt;code&gt;UserPermission&lt;/code&gt; of the user, it is known and the default access for unrestricted app/.. should apply.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;note&#34;&gt;Note:&lt;/h4&gt;
&lt;p&gt;During the sync while reading apps permissions from Front50 (in the app definition), Fiat checks if the app has roles defined for &lt;code&gt;EXECUTE&lt;/code&gt;. If not, Fiat copies the list of roles defined on the app for &lt;code&gt;fiat.executeFallback&lt;/code&gt; (which can be &lt;code&gt;READ&lt;/code&gt; or &lt;code&gt;WRITE&lt;/code&gt;) to the &lt;code&gt;EXECUTE&lt;/code&gt; permission list. This is done to ensure that at least some roles can execute a pipeline as that role has been introduced recently.&lt;/p&gt;
&lt;h3 id=&#34;verifying-access-in-services&#34;&gt;Verifying Access in Services&lt;/h3&gt;
&lt;p&gt;A service checks if user &lt;code&gt;userId&lt;/code&gt; has permission &lt;code&gt;P&lt;/code&gt;  on resource &lt;code&gt;R&lt;/code&gt; of type &lt;code&gt;T&lt;/code&gt; (apps, account, build service). The following steps take place in the service calling Fiat. The response is detailed thereafter.&lt;/p&gt;
&lt;p&gt;If Fiat is not enabled → Yes
If Fiat is enabled → query Fiat with &lt;code&gt;userId&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the local cache first (which expires after &lt;code&gt;services.fiat.cache.expiresAfterWriteSeconds&lt;/code&gt; and defaults to 20)&lt;/li&gt;
&lt;li&gt;If the request fails, retry will back off.  If it keeps failing:
&lt;ul&gt;
&lt;li&gt;if &lt;code&gt;services.fiat.legacyFallback = true&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;T == account&lt;/code&gt;: if the account has at least one &lt;code&gt;WRITE&lt;/code&gt; permission, Yes (TO BE CONFIRMED), otherwise No&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;T == app&lt;/code&gt;: Yes (note: via &lt;code&gt;allowAccessToUnknownApplications&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;T == buildService&lt;/code&gt;: Yes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;else reject&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;if the request succeeds, permissions are returned by Fiat:
&lt;ul&gt;
&lt;li&gt;If the user is admin → Yes&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;T = account&lt;/code&gt; : check that the permission has been returned by Fiat (= permission &lt;code&gt;P&lt;/code&gt; is found for &lt;code&gt;R&lt;/code&gt; in map &lt;code&gt;T&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;T = app&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;if the user has access to the account with the right permission → Yes&lt;/li&gt;
&lt;li&gt;Else if the user does not have any permission set for this app and  &lt;code&gt;permission.allowAccessToUnknownApplications == true&lt;/code&gt; → Yes&lt;/li&gt;
&lt;li&gt;Else reject&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;if &lt;code&gt;T = buildService&lt;/code&gt;: check that the user has the right permission for the build service&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;permissions-returned-by-fiat&#34;&gt;Permissions returned by Fiat&lt;/h3&gt;
&lt;p&gt;Fiat can be asked to return all permissions to a user &lt;code&gt;U&lt;/code&gt;. These permissions are stored in Redis under the following keys &lt;code&gt;spinnaker:fiat:permissions:&amp;lt;user ID&amp;gt;:&amp;lt;resource type&amp;gt;&lt;/code&gt; and store a hash with the following info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt; = name of the resource (e.g. name of the app)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; = &lt;code&gt;{&amp;quot;name&amp;quot;: &amp;lt;name repeated&amp;gt;, &amp;quot;permissions&amp;quot;: { &amp;lt;Permission&amp;gt;: [list of roles] } }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;example&#34;&gt;Example&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;HGETALL spinnaker:fiat:permissions:__unrestricted_user__:applications
1) &amp;quot;app1&amp;quot; 
2) &amp;quot;{\n  \&amp;quot;name\&amp;quot; : \&amp;quot;app1\&amp;quot;,\n  \&amp;quot;permissions\&amp;quot; : { }\n}&amp;quot;
3) &amp;quot;ncecs&amp;quot;
4) &amp;quot;{\n  \&amp;quot;name\&amp;quot; : \&amp;quot;app2\&amp;quot;,\n  \&amp;quot;permissions\&amp;quot; : { }\n}&amp;quot;
5) &amp;quot;cam&amp;quot;
6) &amp;quot;{\n  \&amp;quot;name\&amp;quot; : \&amp;quot;app3\&amp;quot;,\n  \&amp;quot;permissions\&amp;quot; : { }\n}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;permissions-returned&#34;&gt;Permissions Returned&lt;/h3&gt;
&lt;p&gt;Fiat will look up permissions in Redis:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the user is not known to Fiat (edge case, should not happen under normal circumstances but will happen if you try to &lt;code&gt;curl&lt;/code&gt; to Fiat directly) or if there was a communication issue/bug with Redis
&lt;ul&gt;
&lt;li&gt;if &lt;code&gt;fiat.defaultToUnrestrictedUser == true&lt;/code&gt;: treat as the unrestricted user&lt;/li&gt;
&lt;li&gt;else 404 → the request has failed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Merge the permission of the user with the unrestricted user’s permission
&lt;ul&gt;
&lt;li&gt;As a reminder: the unrestricted user only has permissions for resources not constrained.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;permission.isAdmin&lt;/code&gt; to true if the user has been defined as an admin
&lt;ul&gt;
&lt;li&gt;This is true when the user has a role defined in &lt;code&gt;fiat.admin.roles&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;permission.allowAccessToUnknownApplications&lt;/code&gt; to the setting &lt;code&gt;fiat.allowAccessToUnknownApplications&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;summary-of-available-options-in-a-local-config-file&#34;&gt;Summary of available options in a local config file&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth.group-membership.file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Path of the file containing roles and users&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth.group-membership.service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chooses the type of role provider:&lt;br&gt;&lt;br&gt;- &lt;code&gt;file&lt;/code&gt;: File based role provider&lt;br&gt;- &lt;code&gt;github&lt;/code&gt;:  GitHub team role provider&lt;br&gt;- &lt;code&gt;google&lt;/code&gt;: Google Groups role provider&lt;br&gt;- &lt;code&gt;ldap&lt;/code&gt;: LDAP provider&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth.group-membership.github.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Settings for the Github provider&lt;br&gt;&lt;br&gt;- &lt;code&gt;baseUrl&lt;/code&gt;&lt;br&gt;- &lt;code&gt;accessToken&lt;/code&gt;&lt;br&gt;- &lt;code&gt;organization&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth.group-membership.google.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Settings for the Google provider&lt;br&gt;&lt;br&gt;- &lt;code&gt;credentialPath&lt;/code&gt;: Path to the credentials to auth w/ Google&lt;br&gt;- &lt;code&gt;adminUsername&lt;/code&gt;: Email of the Google Apps admin the service account is acting on behalf of&lt;br&gt;- &lt;code&gt;domain&lt;/code&gt;: Domain name in Google Apps&lt;br&gt;- &lt;code&gt;roleSources&lt;/code&gt;: Name of the attributes to map the roles from (can just be &lt;code&gt;NAME&lt;/code&gt; or &lt;code&gt;EMAIL&lt;/code&gt;) - defaults to &lt;code&gt;NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth.group-membership.ldap.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Settings for LDAP provider - DN = Distinguished Name - see LDAP provider above for usage&lt;br&gt;&lt;br&gt;- &lt;code&gt;url&lt;/code&gt;: URL of the LDAP server&lt;br&gt;- &lt;code&gt;managerDN&lt;/code&gt;:  DN of the user Fiat will impersonate to query LDAP&lt;br&gt;- &lt;code&gt;managerPassword&lt;/code&gt;: Password of the user above&lt;br&gt;- &lt;code&gt;groupSearchBase&lt;/code&gt;:&lt;br&gt;- &lt;code&gt;userSearchBase&lt;/code&gt;:&lt;br&gt;- &lt;code&gt;userSearchFilter&lt;/code&gt;:&lt;br&gt;- &lt;code&gt;groupRoleAttributes&lt;/code&gt; (&lt;code&gt;cn&lt;/code&gt;):&lt;br&gt;- &lt;code&gt;groupSearchFilter&lt;/code&gt; (&lt;code&gt;(uniqueMember={0})&lt;/code&gt;):&lt;br&gt;- &lt;code&gt;userDnPattern&lt;/code&gt; (&lt;code&gt;uid={0},ou=users&lt;/code&gt;):&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.getAllEnabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enables the &lt;code&gt;/authorize&lt;/code&gt; endpoint to return all permissions for all users&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.defaultToUnrestrictedUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If true and the user is not defined in Fiat (or Redis operations fail), gives all permissions to the user. This should be an edge case as under normal circumstances all users that have signed in should be known to Fiat.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.allowAccessToUnknownApplications&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If true, this will give a user that has not been given a permission for a specific app any access (read, write, exec) to that app. This is different from an app not having any permissions defined and defaulting to all permissions for all.&lt;br&gt;&lt;br&gt;Here, you can have an app with some permissions (role 1 = READ, role 2 = WRITE) but if user is role 3, they would be unable to gain access to the app. A user with role 1 would be limited to READ.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.executeFallback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;For apps not created with &lt;code&gt;EXECUTE&lt;/code&gt; permissions explicitly, &lt;code&gt;EXECUTE&lt;/code&gt; permissions is given to users with &lt;code&gt;READ&lt;/code&gt; permissions by default. You can change that by setting this to &lt;code&gt;WRITE&lt;/code&gt; (only users with &lt;code&gt;WRITE&lt;/code&gt; would be able to execute the pipeline.)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;READ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.writeMode.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Controlling how Fiat writes to its cache:&lt;br&gt;&lt;br&gt;- &lt;code&gt;enabled&lt;/code&gt; (true)&lt;br&gt;- &lt;code&gt;syncDelayMs&lt;/code&gt; (600000 = 10 minutes): how much effective time between each sync&lt;br&gt;- &lt;code&gt;retryIntervalMs&lt;/code&gt; (10000 = 10s): if sync fails, how much time to wait before retrying&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.admin.roles&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List of roles that grant admin access. Roles listed here are transformed to lower case.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fiat.role.orMode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If true, a user has access to a service account if they have any role defined in the service account roles. &lt;br&gt;By default, it is false and the user needs to have all roles in the service accounts.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;services.fiat.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;These properties are listed here but actually live in services that use Fiat, they dictate how to use Fiat:&lt;br&gt;&lt;br&gt;&lt;br&gt;- &lt;code&gt;refreshable&lt;/code&gt; (true): If true, the service will check every 30s the status of the properties defined here&lt;br&gt;- &lt;code&gt;baseUrl&lt;/code&gt;: Fiat’s base URL&lt;br&gt;- &lt;code&gt;enabled&lt;/code&gt; (false): Is Fiat enabled? &lt;br&gt;- &lt;code&gt;legacyFallback&lt;/code&gt; (false): On a permission retrieval failure, should the user be granted access?&lt;br&gt;- &lt;code&gt;connectTimeoutMs&lt;/code&gt; (none): If set, overrides the OkHTTP connection’s connection timeout when connecting to Fiat&lt;br&gt;- &lt;code&gt;readTimeoutMs&lt;/code&gt; (none): If set, overrides the OkHTTP connection’s read timeout when querying Fiat&lt;br&gt;- &lt;code&gt;cache.expiresAfterWriteSeconds&lt;/code&gt; (20): Expiration of local service cache of Fiat properties &lt;br&gt;- &lt;code&gt;cache.maxEntries&lt;/code&gt; (1000): Max number of items in the local service cache&lt;br&gt;- &lt;code&gt;retry.maxBackoffMillis&lt;/code&gt; (10000): On Fiat request failure, max back off&lt;br&gt;- &lt;code&gt;retry.initialBackoffMillis&lt;/code&gt; (500): Initial backoff on Fiat request failure&lt;br&gt;- &lt;code&gt;retry.retryMultiplier&lt;/code&gt; (1.5): Backoff multiplier&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

      </description>
    </item>
    
  </channel>
</rss>
