I'm writing a go appengine app, which needs to fetch a page from Stripe.
Basically I'm using these instructions that come with the official Stripe API. However, when I run this with dev_appserver.py
, I get:
2016/08/14 12:03:15 Requesting POST api.stripe.com/v1/customers
2016/08/14 12:03:18 Error encountered from Stripe: {"type":"invalid_request_error","message":"Stripe no longer supports API requests made with TLS 1.0. Please initiate HTTPS connections with TLS 1.2 or later. You can learn more about this at https://stripe.com/blog/upgrading-tls.","request_id":"req_90O6reF1Mwi9yZ","status":401}
I found that Python AppEngine apps can specify the SSL library to use in my app.yaml (see SSL support). However, if I add a libraries
section to my app.yaml file, I get:
$ (go_appengine/dev_appserver.py app)
Traceback (most recent call last):
File "go_appengine/dev_appserver.py", line 89, in <module>
_run_file(__file__, globals())
File "go_appengine/dev_appserver.py", line 85, in _run_file
execfile(_PATHS.script_file(script_name), globals_)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/tools/devappserver2/devappserver2.py", line 1040, in <module>
main()
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/tools/devappserver2/devappserver2.py", line 1033, in main
dev_server.start(options)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/tools/devappserver2/devappserver2.py", line 758, in start
options.config_paths, options.app_id)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/tools/devappserver2/application_configuration.py", line 831, in __init__
module_configuration = ModuleConfiguration(config_path, app_id)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/tools/devappserver2/application_configuration.py", line 127, in __init__
self._config_path)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/tools/devappserver2/application_configuration.py", line 424, in _parse_configuration
config, files = appinfo_includes.ParseAndReturnIncludePaths(f)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/api/appinfo_includes.py", line 82, in ParseAndReturnIncludePaths
appyaml = appinfo.LoadSingleAppInfo(appinfo_file)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/api/appinfo.py", line 2191, in LoadSingleAppInfo
listener.Parse(app_info)
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/api/yaml_listener.py", line 227, in Parse
self._HandleEvents(self._GenerateEventParameters(stream, loader_class))
File "/Users/kchodorow/gitroot/tt/go_appengine/google/appengine/api/yaml_listener.py", line 178, in _HandleEvents
raise yaml_errors.EventError(e, event_object)
google.appengine.api.yaml_errors.EventError: libraries entries are only supported by the "python27" runtime
in "app/app.yaml", line 25, column 1
Which makes sense, because I'm not using Python. I really need a way to set this for Go.
My app.yaml file looks like:
application: app-name
version: alpha-001
runtime: go
api_version: go1
handlers:
...
Changing runtime
to python27
gets rid of the library error, but obviously then my go code doesn't work.
Any ideas how to get TLS 1.2 enabled, both with the dev appserver and production?
From Go net/http documentation:
For control over proxies, TLS configuration, keep-alives, compression, and other settings, create a Transport:
tr := &http.Transport{
TLSClientConfig: &tls.Config{...},
DisableCompression: true,
}
client := &http.Client{Transport: tr}
From the appengine documentation it appears you can use the net/http package as usual with a few tweaks.
Please see this oracle blog post. Appengine runs JDK7 and it supports TLSv1.2 but the default protocol is TLSV1
So it first tries to make connection in v1 and if it doesnt support try the other protocols v1.1 and then v1.2
As far as I know you cannot pass {-Dhttps.protocols=TLSv1.2} to GAE but you may be able to set it through code {System.setProperty("https.protocols", "TLSv1.2");}
You should create and setup new transport that has TLS configuration and uses the AppEngine service. It can be done by replacing default dial function with one that is defined by AppEngine SDK (with context).
// NewClient sets up an HTTP/2 client for a certificate and context
func NewClient(ctx context.Context) (*http.Client, error) {
config := &tls.Config{}
transport := &http.Transport{
TLSClientConfig: config,
Dial: func(network, addr string) (net.Conn, error) {
// this uses the appengine service to create the actual client
return socket.Dial(ctx, network, addr)
},
}
return &http.Client{Transport: transport}, nil
}