Search code examples
google-app-enginegoogle-cloud-endpoints

App Engine: Empty referrer error from cron Job when calling Endpoint with restricted API key


I have an App engine app + Cloud endpoints. I have configured a cron task in the task queue to call one of the endpoints. The cron has an auth-constraint to admin.

All of this is working, however when I restrict the api key to certain domains, I get the following error when the cron is run:

Failed check_errors { code: REFERER_BLOCKED detail: "Requests from referer <empty> are blocked." }

It doesn't seem like I can add a referee header to the cron.yaml

apparently Google App Engine issues cron requests from the IP address 0.1.0.1.

so I could potentially allow that ip, but I want to restrict api key by domain not i.p. and it doesn't seem like I can do both

Does anyone know a workaround to allow the cron job access to an api key restricted by domain?


Solution

  • I found a work around for this:

    Note: I see people referencing this in the docs:

    "Calling Google Cloud Endpoints

    You cannot call a Google Cloud Endpoint from a cron job. Instead, you should issue a request to a target that is served by a handler that's specified in your app's configuration file or in a dispatch file. That handler then calls the appropriate endpoint class and method."

    https://cloud.google.com/appengine/docs/standard/java/config/cron#

    Without further explanation or example that I could see.

    I am however able to call my endpoints from a cron job, and it was working fine, other than the api key restraint issue.

    I read several comments on other posts that mention doing a servlet mapping, but without providing an example, so here is the workaround I found and example code for the servlet mapping.

    Java Class

    import java.io.IOException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class MyServlet extends HttpServlet {
        @Override
        public void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
        // call your Endpoint Method here, or whatever you want
            resp.setContentType("text/plain");
            resp.getWriter().println("Hello, world");
        }
    }
    

    web.xml

     <servlet>
            <servlet-name>cronServlet</servlet-name>
            <servlet-class>com.example.MyServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>cronServlet</servlet-name>
            <url-pattern>/cronServlet</url-pattern>
        </servlet-mapping>
    
    <security-constraint>
            <web-resource-collection>
                <web-resource-name>cronServletConstraint</web-resource-name>
                <url-pattern>/cronServlet</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>admin</role-name>
            </auth-constraint>
        </security-constraint>
    

    cron.yaml

    cron:
    - description: myCron
      url: /cronServlet
      schedule: every 12 hours
    

    https://cloud.google.com/appengine/docs/flexible/java/how-requests-are-handled