12

GAE provides cron jobs for scheduled jobs. How do I set some security to prevent someone from executing the http GET directly? In the following example, I can type /updateData anytime in the url field of a browser to execute the job in the following settings:

cron:
- description: daily update of the data in the datastore
  url: /updateData
  schedule: every day 00:00
  timezone: ...
Randy Tang
  • 4,283
  • 12
  • 54
  • 112

4 Answers4

17

In addition to what Paul C said you could create a decorator that checks the X-Appengine-Cron header as illustrated below. Btw, the header can't be spoofed, meaning that if a request that hasn't originated from a cron job has this header, App Engine will change the header's name. You could also write a similar method for tasks, checking X-AppEngine-TaskName in this case.

"""
Decorator to indicate that this is a cron method and applies request.headers check
"""
def cron_method(handler):
    def check_if_cron(self, *args, **kwargs):
        if self.request.headers.get('X-AppEngine-Cron') is None:
            self.error(403)
        else:
            return handler(self, *args, **kwargs)
    return check_if_cron

And use it as:

class ClassName(webapp2.RequestHandler):
    @cron_method
    def get(self):
        ....
nizz
  • 1,133
  • 7
  • 16
  • 2
    Look like that header attribute name is "x-appengine-cron" all lowercase at the moment. Hope that helps someone. – Uzer Aug 26 '20 at 10:18
  • Using nodejs, I did have to work with all lowercase. Thanks @Uzer – Aamir Apr 14 '22 at 17:39
6

You need to add

login: admin

to the hander, as detailed here: Securing URLS for Cron

E.G.

application: hello-cron
version: 1
runtime: python27
api_version: 1

handlers:
- url: /updateData
  script: reports.app
  login: admin
Paul Collingwood
  • 9,053
  • 3
  • 23
  • 36
  • I added `login: admin` and now my cron job receives a 403. – Alex 75 May 02 '17 at 22:49
  • @Alex75 It works to add `login: admin` in app.yaml handler section to secure cron service on Google App Engine standard environment. But on App Engine flex, it changed how to secure your cron handlers like this (PHP example): Check $_SERVER['HTTP_X_APPENGINE_CRON'] and if it's true, the requests are coming from App Engine cron service. – Yao Li May 23 '17 at 15:37
  • "login: admin" checks if the X-Appengine-Cron HTTP header is present – avimimoun Jan 31 '21 at 22:02
0

I am afraid the documentation might not be completely up to date at this point. As Yao Li mentioned, the header you need to check is 'HTTP_X_APPENGINE_CRON' Here is my solution snippet for Python 3.7, Django, and GAE Flex:

from django.http import HttpResponse,HttpResponseForbidden
if 'HTTP_X_APPENGINE_CRON' in request.META:
    if request.META['HTTP_X_APPENGINE_CRON'] == 'true':
        # Handler 
else:
    return HttpResponseForbidden()
Lilo
  • 59
  • 1
  • 6
0

The Google Cloud documentation has some errors.

  1. The request header should be x-appengine-cron (all lowercase!) and the expected value is "true" as a string.
  2. The source IP address x-forwarded-for has to start with 10. (as in the internal network IP 10.1.1.1) or 0. (as in the local IP 0.1.0.2).
oebilgen
  • 41
  • 4