I've read some info about authentication, but I would have thought that I could turn off my app's visibility and/or access to the public. This would be useful for alpha testing so surely a setting like this exists? Or do I need to build such things into the app itself?
Without some sort of authentication mechanism your app can't really distinguish between a request coming from you and one coming from someone else.
It might be a good idea to spend a bit of time to analyze your app's authentication requirements and maybe get it done now, while still in alpha.
Depending on the solution it may be fairly simple to integrate.
Google offers multiple authentication options, see What is the difference between Google identity toolkit, Google OAauth and Google+ sign in
I personally opted for the GIT kit for simplicity, flexibility and convenience.
It's possible secure your App's urls so only an authorised user or administrator can access them.
This can be done through the app.yaml file (Python, PHP and Go applications) or the web.xml deployment descriptor (Java applications).
Option A:
Just allow only admin access, in yourapp.yaml
- url: /*
login: admin
script: yourappname.app
Option B:
If you have an static IP (or with a few changes a week), you can detect the IP of the request and let run only from your IP:
class yourHandler(webapp2.RequestHandler):
def get(self):
userIP=self.request.remote_addr
if userIP=="220.123.211.120" # Change this with your static IP
...your code for authorized users.
Option C:
Check request domain (to ensure is called from your own authorized domains), and put some security client side.
class yourHandler(webapp2.RequestHandler):
def get(self):
origin=self.request.headers['Origin']
if origin=="www.yourdomain.com" # Change this with your domain/subdomain
...your code for authorized users.
# I recommend to put also the CORS headers for your own domain
self.response.headers['Access-Control-Allow-Origin'] = "www.yourdomain.com"
Personally, I have a mix of the three options plus a custom authentication to access private content.
By default, every service is born public. Change that, individually, by changing the --ingress setting for the service you want.
gcloud beta app services update <service-name> --ingress <value>
all (default): public to internet.
internal-only: only accessible for resources in the same Cloud Project.
internal-and-cloud-load-balancing: only accessible for resources in the same Cloud Project. And those requests came from configured Cloud Load Balancing.
1 Gateway + a bunch Microservices architecture example:
gcloud beta app services update ms-payment --ingress internal-only
gcloud beta app services update my-backend-gateway --ingress all << default!! Just for example purpose.
In this way, ms-payment is accessible only by resources within the same Cloud Project, even if they are in different VPCs.
Refer the documentation: https://cloud.google.com/appengine/docs/standard/java11/application-security#ingress_controls
I've found recently that you could also use IAP (Identity-Aware Proxy) IA-what? I found a tutorial that implements it on App Engine.
Tutorial for App Engine.
So I didn't want to rely on my own authentication implementation because I'm not an expert, and security it's something very hard to learn in a rush. In a nutshell
Deploy an IAP step 1
Add your app engine (or the whole scope) to your IAP
add your authorized emails on the left panel step 3. For access use:
IAP-Secured Web App User: Grants access to the app and other HTTPS
resources that use IAP.
My Personal opinion here: try to implement as many safety measures as possible (don't rely on one system only), usually they could fail.
Related
I have a service in Google Cloud App engine, which is behind IAP.
It is accessible only to users within my organisation.
I need to make a few endpoints of this service accessible for all users.
Is it possible to achieve?
I have found an instruction, which says that it is possible, but it also says: The allUsers and allAuthenticatedUsers values are unsupported member types in a conditional role binding. If you specify one of these member types, the setIamPolicy operation will fail.
Which is not clear for me and a bit confusing.
A small example:
My service has an url https://google-cloud-app-engine-service.com
And I want to make only one endpoint of this service available to everyone:
https://google-cloud-app-engine-service.com/public_endpoint.
Thank you!
You can't white list URL path with IAP. The finest grain is the service. I mean, you can activate IAP on AppEngine. Then, for the service that you want you can select it, go to the info panel and add allUsers or allAuthenticatedUsers with the role IAP-secured web app user
You have several alternatives
Manage the security by yourselves and don't use IAP (which is not a good idea)
Use Cloud Endpoint in front of your AppEngine. I wrote an article on this for securing with APIKey, but you can change the security definition is you want. The problem is that you have to define all your API in the Cloud Endpoint, and you have an additional component in your stack
Use 2 services (if possible). Set one public and the other protected by IAP.
As #guillaume-blaquiere suggested in his answer, I split my app engine service by two independent services and made the first one only accessible from within my organization and the second one to everyone using IAP.
In Google App Engine, I have 3 services, 1 for front end, 2 for back end.
Is there a way to block http calls to my backend services for accounts not from my company's domain (and the service account of the front end), but allow everyone http access to my front end service?
I know there is the firewall option, but this is restricted to IP addresses, I would prefer user based
If it matters all services are python3
There's currently no option to filter traffic to specific App Engine services within a single application/project:
App Engine Firewall filters by source IP ranges but can only be set for the whole app, not per service.
Identity-Aware Proxy can filter access by user account as you'd prefer but also applies to the whole app. Also, it only supports user account and can't be used with service accounts.
One option you may have would be to split your app in 2 different projects. Keep the front-end in one project open to the world and restrict access to the backend services in your other project via firewall rules.
I have seen the following being used in task queues in GAE. Maybe it would help.
If u were using python 2, in standard environment, i think u could have used login handler element in app.yaml file.
You could have added following lines to your app.yaml file:
handlers:
- url: /.*
script: worker.app
login: admin
This prevents other users from accessing this service.
But the same login handler is not available for python3, according to Google Docs.
Just found following in Google Docs:
If a task performs sensitive operations (such as modifying data), you might want to secure the handler URL to prevent a malicious external user from calling it directly. You can prevent users from accessing task URLs by restricting access to App Engine administrators. Task requests themselves are issued by App Engine and can always target a restricted URL.
You can restrict a URL by adding the login: admin element to the handler configuration in your app.yaml file.
You can also call your backend services through cloud tasks or task queues (both are almost the same i guess), in case this only work for cloud tasks.
Find the code usage here:
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/6f5f3bcb81779679a24e0964a6c57c0c7deabfac/appengine/standard/taskqueue/counter
Find details about handler here.
https://cloud.google.com/appengine/docs/standard/python/config/appref#handlers_element
Find details about Cloud task and queue here:
https://cloud.google.com/appengine/docs/standard/python/taskqueue/push/creating-handlers
How to restrict access to GAE Flexible site only for all account from my domain in GSuite and eventually other Google accounts that I provide explicitely. AFAIR there where something simillar in Standard GAE version in app.yaml handlers section.
So my scenario:
prodution versions restricted until go-live
dev and stage version restricted permanently
I would like to do this on the IAM level, to reject traffic to the site. But I didn't found anything in docs.
Ok, after rethink the problem and dig deeper in a documentation I found a page about dev environment - https://cloud.google.com/appengine/docs/standard/python/creating-separate-dev-environments.
So my current solution is not to have separate versions like dev, stage and prod and work with them within one project, but to create separate projects for each of environment.
It will also simplify management of DBs - previous I thought about different database in one DB server for particular environment. Now I will have a separate DB instance for it.
Anyway I still have a problem with securing access.
I did it in the same way like in Restrict App Engine access to G Suite accounts on custom domain:
changed Google Authentication to my Google Suite domain
added Custom Domain in my app
added my page domain to my GSuite as a second domain
And I still can connect to my page without auth - even in "Incognito mode" and on others computers and mobiles.
EDIT:
As a workaround I used Django-lockdown module. For the timebeing is more than enough - I have a password, I have a session, I can set it in Middleware or as a decorator for urls.
EDIT 2:
I noticed today a new feature in GAE Flexible - Identity-Aware Proxy.
This is the feature, that I was searching. You can restrict accces by:
Google Account email: user#gmail.com
Google Group: admins#googlegroups.com
Service account: server#example.gserviceaccount.com
Google Apps domain: example.com
We are starting a very large web based service project. We are trying to decide what hosting environment to use. We would really like to use Google App Engine for scalability reasons and to eliminate the need to deal with servers ourselves.
Secure logins/registrations is very important to us, as well as using our own domain. Our target audience is not very computer savvy. For this reason, we don't want to have the users have to sign up with OpenID as this can't be done within our site. We also do not want to force our customers to sign up with Google.
As far as I can see, I am out of luck. I am hoping to have a definite answer to this question. Can I have an encrypted login to our site accessed via our domain, without having to send the customers to another site for the login (OpenID/Google).
Thanks.
The hardest part is getting around the cookie issue. While you can do secure and custom logins against https://yourdomain.appspot.com, you cannot set a cookie there that will work on http://yourdomain.com.
Here is what I propose:
When you need to log the user in, send them to https://yourdomain.appspot.com. If they enter the credentials properly, create a one-time token and place it either in the datastore or in memcache. Give it a lifetime of a few seconds.
Then redirect the user back to http://yourdomain.com/authenticate?token=mytoken (obviously substitute the names as appropriate), check to make sure that the token is valid and has not expired, and if all is clear, set the appropriate cookies and expire the token.
I think that'd work just fine. Hope it helps!
As of June 27, 2012, App Engine supports SSL for custom domains.
http://googleappengine.blogspot.com/2012/06/google-app-engine-170-released-at.html
There is nothing stopping you from creating your own authentication/registration mechanism with Google App Engine. The only problem is that Google App Engine currently only supports HTTPS via https://yourid.appspot.com and not your Google Apps Domain (i.e. https://www.foobar.com). However, this is on the product roadmap for future support (SSL for third-party domains). Note, also on the product roadmap is built-in support for OAuth & OpenID.
Update: Another option may be to use a proxy server (like Apache with mod_proxy) and map your domain to the proxy server and then the proxy server can proxy the HTTP and HTTPS requests to Google App Engine. The requests could be proxied to the appspot.com domain behind the scenes. I haven't actually done this, but I believe it should work. However, this would give you a single point of failure at the proxy server which basically defeats the purpose of Google App Engine's high-availability and scalability. This would definitely just be a short-term solution until Google supports SSL for third-party domains or OpenID.
Depending on whether your threat model can accept a non-encrypted link on the "last hop" to GAE, you can use a proxy to handle SSL from the browser. Here's a HOWTO I wrote up on using CloudFlare to get always-on SSL:
http://blorn.com/post/20185054195/ssl-for-your-domain-on-google-app-engine
This isn't structurally any different than the way SSL from Google will work, it's just that Google-provided SSL will terminate within G's network rather than just outside it. If you're trying to protect against Firesheep, CloudFlare (or any other SSL proxy) will do fine. If you're worried about snoops on the trunk connection between CF and Google, you may want a more sophisticated solution.
I've been fooling around with the Google App Engine for a few days and I have a little hobby application that I want to write and deploy.
However I'd like to set it up so that users are not directly accessing the app via appspot.com.
Is hosting it through Google Apps and then pointing it at my own domain the only way to go? I looked at that a little bit and it seemed like a pain to implement but maybe I'm just missing something.
My other thought was to write the app-engine piece as a more generic web-service.
Then I could have the user-facing piece be hosted anywhere, written in any language, and have it query the appspot.com url.
Anyone have any luck with the web-service approach?
The reason Google Apps is required is because you need somewhere to a) verify you own the domain (otherwise, you might point it at app engine, then I might hijack it by adding it to my account) and b) set up domain mappings (which subdomains point to which of your appengine apps).
Since this stuff already exists in Apps, it seems silly to duplicate it in AppEngine.
As has been pointed out, it doesn't cost anything, and you do not need to "move" anything to Google. You simple created a cname record with a random name to verify you own the domain, and a cname for the subdomain you wish to point at App Engine. This only takes a few minutes, and once it's done, it's done forever.
Note: If you host your site elsewhere and use webservices, you need to scale the site/frontend. If you host on app engine, you get this for free :-)
I wrote an article on my blog about redirecting *.appspot.com domains to your custom domain to keep your branding:
http://blog.dantup.com/2009/12/redirecting-requests-from-appid-appspot-com-to-a-custom-domain
To do this, I believe you need to be using Google Apps and have a custom domain setup for Google Apps. Then, you deploy your app into your Google Apps domain.
Here is google's official instructions on how to do that:
http://code.google.com/appengine/docs/domain.html
I have used this process for a couple of sites and it is easy and painless, provided you have control on the DNS records for your domain (you should).
OK, we're now at the end of 2017 and things are a lot different regarding App Engine and custom domains. It's easy now!
Go to the app engine dashboard for your app and choose Settings, then go to the Custom Domains tab. From there, choose Add custom domain.
The tricky part is that Google needs to verify that you control the domain, so they ask you to put a TXT record in the DNS for your domain. Once you do that and Google it, you become "verified" as the owner of the domain.
After that, Google will give you a bunch of A and AAAA (for IP6) records to put in your DNS. Once you've done that, you should be good to go.
It can be easily done using request.getRequestURI() method. If the URL doesn't include your domain, just redirect it to the desired URL using
resp.sendRedirect("<your domain>")
Otherwise load a error page using
request.getRequestDispatcher("<error-page>").forward(request, response);