Using flat-manager for private app repo

Alexander Larsson alexl at redhat.com
Fri May 3 08:44:11 UTC 2019


On Thu, May 2, 2019 at 6:13 PM Dan Nicholson <nicholson at endlessm.com> wrote:
>
> On Tue, Apr 30, 2019 at 11:11 AM Alexander Larsson <alexl at redhat.com> wrote:
> >
> > On Tue, Apr 30, 2019 at 5:30 PM Dan Nicholson <nicholson at endlessm.com> wrote:
> >
> > Do you mean one token with everything the user has access to? Seems
> > like that could end up very large. And anyway, to avoid risk of
> > leaking such a token we need to time limit it anyway, so generating a
> > token per download seems to make more sense.
>
> Yeah, that would probably be a little nicer at the expense of
> requiring tokens more often.

Yeah, but that is not too bad. We should only need the token when
actually doing the update. Like, we can look at the summary file
without it and this filters out most update calls as no-ops, then we
only need a token when there is an actual download.

> > > > Then the repo server (like flat-manager) can know that certain (or
> > > > all) refs require authentication and what signatures are needed to
> > > > download those files.
> > >
> > > I'm not sure what you mean here. How does the repo server know what
> > > refs require authentication and what the allowed signature are?
> >
> > All the CDN sees is a download of e.g. 04/232121244.commit. Say the
> > token says the user is allowed to download "org.cool.Game", and that
> > is part of the token. How does the CDN match the url being downloaded
> > to the required token? Well, we could have the upstream flatp-manager
> > set some http header in the reply (for all apps that require a token),
> > specifying which tokens are needed. Then the CDN can do the upstream
> > request once and cache this header, letting future requests be cache
> > only.
> >
> > So, something like:
> >
> > user asks central server for a token for org.cool.Game
> > user passes token to CDN request
> > CDN does upstream request, gets back result + header that says "need
> > org.cool.Game token"
> > CDN verifies passed token based on header + current time
> > CDN returns results
> >
> > On a second call the CDN can use a cached value for the token and
> > avoid an upstream request.
>
> That would be really nice, but I fear it would be highly CDN specific.
> It would basically require lifting the application logic into the CDN.
> That looks somewhat possible with Fastly which uses Varnish and allows
> you to provide customized hooks. And now that I look again even our
> CDN provides a way to use URL tokens.
>
> So, probably there is a way to make the CDN edge server handle
> authorization, although it would be specific to the CDN provider. That
> said, I think it should be possible to deploy a private app store
> without also requiring on a CDN. In other words, I think it should be
> possible to handle the authorization at both the origin and edge
> server.

Yes, I think most CDNs support *something* like this, because it is
how everyone seems to implement things like private or for-pay
downloads. So, what we need to do is to look at the most common CDNs
and make sure that the methods we support allows implementations on
all (or most) of these. Of particular importance are fastly (for
flathub) and whatever CDNs endless ends up using.

> One thing that could be useful is an API endpoint that takes a ref and
> returns a list of commit and delta superblock URL paths. Then the
> authorization server could generate the proper signed URLs in the
> format the CDN needed after determining that the user was allowed to
> access a specific ref. I don't know, I haven't quite been able to
> figure out how this would go.

I'm not sure what this would be used for. This is like moving to the
client the set of urls you're required to supply a token for. But that
seems backwards, it is the CDN (or proxy or whatever) that need to
know if a url needs a token, we can't trust the client in this. How
did you imagine this API being used?

We do however need to know this. But I don't think you ever need this
full list? Instead what the client does is look at the summary file,
figures out which commit and delta uris to download, and then just
does it, passing in the token the auth server gave it (for this ref)
to every such request. Then the CDN/flat-manager needs to know if this
particular ref requires a token, and if so which token.

This can happen in two ways:
1 ) The check happens directly in flat-manager, where it just returns
a 403 error if the token is missing
2) The check happens in the CDN, but it has no idea initially, so it
proxies the request to flat-manager, and flat-manager knows which/if
any token is needed, and returns the result + a header telling the cdn
which token it needs to apply.

This is how we support both direct and CDNed access control. Maybe
flat-manager has a known list of CDN ip address sources where it does
2, and otherwise it does 1. Or maybe the CDN sets some magic secret
when proxying.

Of course, this all means that flat-manager needs to know for each
commit/delta url request what token is required. Each commit object
has the ref bindings in them, and each delta superblock file has a
copy of the commit object, so it would be easy for flat-manager to
extract these if the url format matches, and either verify the header
or set the ref in a header in the response. Actually, it would
probably be fine to just always set it in the response to a commit or
delta superblock request.

The question then becomes, given the ref, how do we know if the app
has access to it. The simplest way I can think of is:
 1) Make the token contain a list of ref globs, like "*/org.the.app*/*/stable"
2) Split free and for-pay refs into different repos and apply token
requirements to all downloads in the for-pay repo.

The alternative to 2 is to mark up each ref somehow, but it seems
easier both from a server side and client side (you need to figure out
when you need to request a token) to have this be a global option per
repo.

This doesn't seem *that* hard, although its going to need some work:
1) Support in ostree/flatpak for a needs-token per-remote config where
we go to an auth server and get a token for all refs required in a
pull. Actually, this might not actually need to touch the ostree code,
it might be possible to user the http-headers option of
ostree_repo_pull_with_options().
2) Support in flat-manager to extract the ref bindings for commit and
delta superblock files
3) Support in flat-manager to optionally verify ref binding vs the
token (this should probably use a separate secret from the one used
for auth:ing the build APIs, and probably a different, simpler token
format).
4) Research into various CDN configurations

Most of this looks relatively simple actually. The most problematic
part is probably going to be the API to the authentication server. In
particular how you authenticate to that. The details of this
authentication is likely to be different for every repo provider (user
+ password, email + password, api token, etc) and the secret will have
to be stored somewhere in the flatpak configuration, or provided in
some secure way. This must both be flexible and secure, which is a
hard combination.

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                Red Hat, Inc
       alexl at redhat.com         alexander.larsson at gmail.com


More information about the Flatpak mailing list