All Products
Search
Document Center

1. Use a proxy to handle floating IP address issues

Last Updated: May 31, 2019

This section introduces how to use function A to access a service configured with access control and use function B to access a third-party service with access control.

Function A uses HTTP triggers to receive a request from external users, and then access function B to obtain the protected resources while processing the request. If function A obtains the resources, it proceeds to process the request. Otherwise, it stops.

Function B also uses HTTP triggers. Function B uses a whitelist to authenticate visitors and returns the requested resources when the visitors are validated. If the visitors fail to pass the authentication, an authentication error is returned.

Use ECS to build a proxy server and use NGINX to provide the proxy service.

Create functions for services A and B

  1. Log on to Function Compute console.

  2. See Service operation to create service A and service B.

  3. In the left-side navigation pane, click and enter the corresponding service page.

  4. Click Create Function in the service, go to the function creation page and perform the following tasks:

    1. Click Select All and choose Python2.7 from the drop-down list. All code in this example is based on Python.

    2. Select Empty Function.

    3. Select No Trigger.

    4. Create the function and specify the service name, function name, description, and runtime.

    5. Click Next.

    6. Make sure that all information is correct and then click Create.

  5. Write code.

    • Function A is created by using an HTTP trigger. You can directly copy the following code to function A and then click Save.

    • Function B is created by using the Django framework. Therefore, you must use command-line tool fcli or Python SDK to upload the code package. You can also use Object Storage Service (OSS) or directly upload a ZIP file.

  6. Create an HTTP trigger for both function A and function B.

If you have any issues during HTTP trigger creation, reference the document Samples of HTTP triggers.

Now service A and service B are successfully built. However, you cannot use service A to call service B to obtain permissions because the whitelist in function B only contains the public IP address of the proxy server. The following shows the content of functions A and B.

Write function A

Function A is triggered by using an HTTP trigger.

Write function

Function sample descriptions:

  • A handler is a function that the system can run when executing the code. It contains the logic for simulating the results of invoking function B with and without using the proxy.

  • get_data_by_url contains the logic for invoking function B.

  • my_http_request is used to send HTTP requests through the proxy.

  1. # -*- coding: utf-8 -*-
  2. import logging
  3. import urllib, urllib2, sys
  4. import ssl
  5. import json
  6. # Proxy service address
  7. proxy_address = 'ip:port'
  8. # Function B service address
  9. data_service_host = 'https://{id}.{region}.fc.aliyuncs.com'
  10. data_service_path = '/service/path'
  11. def handler(environ, start_response):
  12. """
  13. entrance
  14. """
  15. url = data_service_host + data_service_path
  16. # Use a proxy
  17. proxy_result = get_data_by_url(url, proxy_address)
  18. # Not use a proxy
  19. normal_result = get_data_by_url(url, None)
  20. # Return and display the results of getting data with and without the proxy
  21. result = {
  22. "query_with_proxy_result": proxy_result,
  23. "query_without_proxy_result": normal_result
  24. }
  25. status = '200 OK'
  26. response_headers = [('Content-type', 'text/json')]
  27. start_response(status, response_headers)
  28. return json.dumps(result)
  29. def get_data_by_url(url, proxy):
  30. """
  31. Encapsulate user requests
  32. """
  33. result = {
  34. "success": False,
  35. "secret_data": '',
  36. "data_service_raw_data": {}
  37. }
  38. content = my_http_request(url, proxy)
  39. if content:
  40. content = json.loads(content)
  41. result["data_service_raw_data"] = content
  42. # Simulate requested data processing
  43. if "authorized" in content and content["authorized"]:
  44. result["success"] = True
  45. result["secret_data"] = content["protected_data"]
  46. return result
  47. def my_http_request(url, proxy=None):
  48. """
  49. Request with proxy information
  50. """
  51. try:
  52. ret = None
  53. socket_fd = None
  54. request = urllib2.Request(url)
  55. request.add_header('User-Agent', 'Fake_browser/1.0')
  56. if proxy:
  57. request.set_proxy(proxy, 'http')
  58. opener = urllib2.build_opener()
  59. socket_fd = opener.open(request)
  60. ret = socket_fd.read()
  61. except Exception as e:
  62. ret = json.dumps({"info": "exception in proxy query: %s" % e})
  63. finally:
  64. if socket_fd:
  65. socket_fd.close()
  66. return ret

Write function B

In function B, use Django to build a Web service and set a whitelist for authentication. Data is returned only when the visitors pass the authentication. The structure of the code is as follows:

  1. project/
  2. ├── lib
  3. ├── Django-1.11.13.dist-info
  4. ├── django
  5. ├── pytz
  6. └── pytz-2018.4.dist-info
  7. ├── main.py
  8. └── src
  9. ├── __init__.py
  10. ├── bin
  11. ├── __init__.py
  12. └── manage.py
  13. ├── conf
  14. ├── __init__.py
  15. ├── settings.py
  16. ├── urls.py
  17. └── wsgi.py
  18. ├── data
  19. └── views
  20. ├── __init__.py
  21. └── view.py

The code shows the structure of the code package.

Write function

  1. Function entry
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. import sys
  4. import os
  5. # load local django
  6. sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + '/lib')
  7. sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
  8. import django
  9. print (django.__version__)
  10. import views.view
  11. from conf.wsgi import application
  12. def handler(environ, start_response):
  13. import urlparse
  14. parsed_tuple = urlparse.urlparse(environ['fc.request_uri'])
  15. li = parsed_tuple.path.split('/')
  16. global base_path
  17. if not views.view.base_path:
  18. views.view.base_path = "/".join(li[0:5])
  19. return application(environ, start_response)
  1. urls.py
  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from views import view
  4. urlpatterns = [
  5. url(r'^index$', view.index),
  6. url(r'^get_data$', view.get_data),
  7. ]
  1. views.py
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. from django.http import HttpResponse
  4. from django.conf import settings
  5. import logging
  6. import json
  7. logger = logging.getLogger()
  8. base_path = ""
  9. def index(request):
  10. """
  11. Testing entry
  12. """
  13. logger.info("Django request detected! url: index")
  14. white_list = settings.WHITE_LIST
  15. allowed_hostlist = ' '
  16. for allowed_host in white_list:
  17. allowed_hostlist += allowed_host
  18. allowed_hostlist += ' '
  19. return HttpResponse("<h1>It works! Copyright: jianyi</h1> Whitelist: %s" % allowed_hostlist, status=200)
  20. def get_data(request):
  21. """
  22. Operation for obtaining data
  23. """
  24. result = {
  25. "remote_ip": '',
  26. "white_list": [],
  27. "authorized": False,
  28. "protected_data": ''
  29. }
  30. if request.META.has_key('HTTP_X_FORWARDED_FOR'):
  31. remote_ip = request.META['HTTP_X_FORWARDED_FOR']
  32. else:
  33. remote_ip = request.META['REMOTE_ADDR']
  34. result["remote_ip"] = remote_ip
  35. result["white_list"] = settings.WHITE_LIST
  36. if remote_ip in result["white_list"]:
  37. result["authorized"] = True
  38. result["protected_data"] = "Alibaba"
  39. return HttpResponse(json.dumps(result), status=200)
  1. settings.py

Add the whitelist setting to the bottom of the default settings.py file: add the public IP address of the proxy server to the whitelist.

  1. # User conf
  2. WHITE_LIST = [
  3. "127.0.0.1",
  4. "xx.xx.xx.xx"
  5. ]

Build a proxy

Use NGINX to provide the proxy service. You can deploy NGINX on an ECS instance or a normal server. After the deployment is complete, set the proxy settings in the configuration file as follows:

  1. server{
  2. resolver x.x.x.x;
  3. listen 8080;
  4. location / {
  5. proxy_pass http://$http_host$request_uri;
  6. }
  7. }

Notes:

  • Do not include the hostname.
  • You must include the resolver (DNS). Replace x.x.x.x in the proxy settings with the IP address of the DNS resolver.
  • Do not change NGINX system variables $http_host and $request_uri.
  • In the actual environment, we recommend that you use NGINX or Keepalived to build SLB clusters and proxy clusters to provide proxy service. This improves the availability and performance of the system.

To view the DNS resolver information, run the cat /etc/resolv.conf command.

You can start testing after uploading the code of functions A and B and starting NGINX.

What to do next

Testing procedure and results