Skip to content

Commit f66db37

Browse files
author
Daniel Mikusa
authored
Adds external configuration support for Luna Security Module (#879)
- Extracts external configuration code into a utility - Modifies AppDynamics to use the utility code - Modifies Luna Security Provider to use the utility code - Updates documentation for AppDynamics and Luna to explaini how external configuration works
1 parent 751b453 commit f66db37

File tree

7 files changed

+364
-79
lines changed

7 files changed

+364
-79
lines changed

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ GEM
1515
public_suffix (4.0.4)
1616
rainbow (3.0.0)
1717
rake (13.0.1)
18-
rexml (3.2.5)
1918
redcarpet (3.5.1)
19+
rexml (3.2.5)
2020
rspec (3.9.0)
2121
rspec-core (~> 3.9.0)
2222
rspec-expectations (~> 3.9.0)
@@ -69,4 +69,4 @@ DEPENDENCIES
6969
yard
7070

7171
BUNDLED WITH
72-
2.1.4
72+
2.2.16

docs/framework-app_dynamics_agent.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,51 @@ The framework can be configured by modifying the [`config/app_dynamics_agent.yml
4444
| `version` | The version of AppDynamics to use. Candidate versions can be found in [this listing][].
4545

4646
### Additional Resources
47-
The framework can also be configured by overlaying a set of resources on the default distribution. To do this, add files to the `resources/app_dynamics_agent` directory in the buildpack fork. For example, to override the default `app-agent-config.xml` add your custom file to `resources/app_dynamics_agent/<version>/conf/app-agent-config.xml`.
47+
The framework can also be configured by overlaying a set of resources on the default distribution. To do this follow one of the options below.
48+
49+
Configuration files are created in this order:
50+
51+
1. Default AppDynamics configuration
52+
2. Buildpack default configuration is taken from `resources/app_dynamics_agent/default`
53+
3. External Configuration if configured
54+
4. Local Configuration if configured
55+
5. Buildpack Fork if it exists
56+
57+
#### Buildpack Fork
58+
Add files to the `resources/app_dynamics_agent` directory in the buildpack fork. For example, to override the default `app-agent-config.xml` add your custom file to `resources/app_dynamics_agent/<version>/conf/app-agent-config.xml`.
59+
60+
#### External Configuration
61+
Set `APPD_CONF_HTTP_URL` to an HTTP or HTTPS URL which points to the directory where your configuration files exist. You may also include a user and password in the URL, like `https://user:[email protected]`.
62+
63+
The Java buildpack will take the URL to the directory provided and attempt to download the following files from that directory:
64+
65+
- `logging/log4j2.xml`
66+
- `logging/log4j.xml`
67+
- `app-agent-config.xml`
68+
- `controller-info.xml`
69+
- `service-endpoint.xml`
70+
- `transactions.xml`
71+
- `custom-interceptors.xml`
72+
- `custom-activity-correlation.xml`
73+
74+
Any file successfully downloaded will be copied to the configuration directory. The buildpack does not fail if files are missing.
75+
76+
#### Local Configuration
77+
Set `APPD_CONF_DIR` to a relative path which points to the directory in your application files where your custom configuration exists.
78+
79+
The Java buildpack will take the `app_root` + `APPD_CONF_DIR` directory and attempt to copy the followinig files from that directory:
80+
81+
- `logging/log4j2.xml`
82+
- `logging/log4j.xml`
83+
- `app-agent-config.xml`
84+
- `controller-info.xml`
85+
- `service-endpoint.xml`
86+
- `transactions.xml`
87+
- `custom-interceptors.xml`
88+
- `custom-activity-correlation.xml`
89+
90+
Any files that exist will be copied to the configuration directory. The buildpack does not fail if files are missing.
91+
4892

4993
[`config/app_dynamics_agent.yml`]: ../config/app_dynamics_agent.yml
5094
[AppDynamics Java Agent Configuration Properties]: https://docs.appdynamics.com/display/PRO42/Java+Agent+Configuration+Properties

docs/framework-luna_security_provider.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,27 @@ The framework can be configured by modifying the [`config/luna_security_provider
9898
| `version` | Version of the Luna Security Provider to use.
9999

100100
### Additional Resources
101-
The framework can also be configured by overlaying a set of resources on the default distribution. To do this, add files to the `resources/luna_security_provider` directory in the buildpack fork.
101+
The framework can also be configured by overlaying a set of resources on the default distribution. To do this follow one of the options below.
102+
103+
Configuration files are created in this order:
104+
105+
1. Default configuration
106+
2. Buildpack fork
107+
3. Buildpack generated configuration if the bound service has both a `servers` and `groups` key
108+
4. External configuration if configured
109+
110+
#### Buildpack Fork
111+
Add files to the `resources/luna_security_provider` directory in the buildpack fork. For example, to override the default `Chrystoki.conf` add your custom file to `resources/luna_security_provider/Chrystoki.conf`.
112+
113+
#### External Configuration
114+
Set `LUNA_CONF_HTTP_URL` to an HTTP or HTTPS URL which points to the directory where your configuration files exist. You may also include a user and password in the URL, like `https://user:[email protected]`.
115+
116+
The Java buildpack will take the URL to the directory provided and attempt to download the following files from that directory:
117+
118+
- `Chrystoki.conf`
119+
- `server-certificates.pem`
120+
121+
Any file successfully downloaded will be copied to the configuration directory. The buildpack does not fail if files are missing.
102122

103123
[`config/luna_security_provider.yml`]: ../config/luna_security_provider.yml
104124
[Luna Security Service]: http://www.safenet-inc.com/data-encryption/hardware-security-modules-hsms/

lib/java_buildpack/framework/app_dynamics_agent.rb

Lines changed: 19 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@
1919
require 'shellwords'
2020
require 'java_buildpack/component/versioned_dependency_component'
2121
require 'java_buildpack/framework'
22+
require 'java_buildpack/util/external_config'
2223

2324
module JavaBuildpack
2425
module Framework
2526

2627
# Encapsulates the functionality for enabling zero-touch AppDynamics support.
2728
class AppDynamicsAgent < JavaBuildpack::Component::VersionedDependencyComponent
29+
include JavaBuildpack::Util::ExternalConfig
30+
31+
# Full list of configuration files that can be downloaded remotely
32+
CONFIG_FILES = %w[logging/log4j2.xml logging/log4j.xml app-agent-config.xml controller-info.xml
33+
service-endpoint.xml transactions.xml custom-interceptors.xml
34+
custom-activity-correlation.xml].freeze
35+
36+
# Prefix to be used with external configuration environment variable
37+
CONFIG_PREFIX = 'APPD'
2838

2939
def initialize(context)
3040
super(context)
@@ -40,7 +50,7 @@ def compile
4050
default_conf_dir = resources_dir + @droplet.component_id + 'defaults'
4151

4252
copy_appd_default_configuration(default_conf_dir)
43-
override_default_config_remote
53+
override_default_config_remote(&method(:save_cfg_file))
4454
override_default_config_local
4555
@droplet.copy_resources
4656
end
@@ -71,13 +81,9 @@ def supports?
7181

7282
private
7383

74-
CONFIG_FILES = %w[logging/log4j2.xml logging/log4j.xml app-agent-config.xml controller-info.xml
75-
service-endpoint.xml transactions.xml custom-interceptors.xml
76-
custom-activity-correlation.xml].freeze
77-
7884
FILTER = /app[-]?dynamics/.freeze
7985

80-
private_constant :CONFIG_FILES, :FILTER
86+
private_constant :FILTER
8187

8288
def application_name(java_opts, credentials)
8389
name = Shellwords.escape(@application.details['application_name'])
@@ -150,67 +156,6 @@ def copy_appd_default_configuration(default_conf_dir)
150156
end
151157
end
152158

153-
# Check if configuration file exists on the server before download
154-
# @param [ResourceURI] uri URI of the remote configuration server
155-
# @param [ConfigFileName] conf_file Name of the configuration file
156-
# @return [Boolean] returns true if files exists on path specified by APPD_CONF_HTTP_URL, false otherwise
157-
def check_if_resource_exists(resource_uri, conf_file)
158-
# check if resource exists on remote server
159-
begin
160-
opts = { use_ssl: true } if resource_uri.scheme == 'https'
161-
response = Net::HTTP.start(resource_uri.host, resource_uri.port, opts) do |http|
162-
req = Net::HTTP::Head.new(resource_uri)
163-
if resource_uri.user != '' || resource_uri.password != ''
164-
req.basic_auth(resource_uri.user, resource_uri.password)
165-
end
166-
http.request(req)
167-
end
168-
rescue StandardError => e
169-
@logger.error { "Request failure: #{e.message}" }
170-
return false
171-
end
172-
173-
case response
174-
when Net::HTTPSuccess
175-
true
176-
when Net::HTTPRedirection
177-
location = response['location']
178-
@logger.info { "redirected to #{location}" }
179-
check_if_resource_exists(location, conf_file)
180-
else
181-
@logger.info { "Could not retrieve #{resource_uri}. Code: #{response.code} Message: #{response.message}" }
182-
false
183-
end
184-
end
185-
186-
# Check for configuration files on a remote server. If found, copy to conf dir under each ver* dir
187-
# @return [Void]
188-
def override_default_config_remote
189-
return unless @application.environment['APPD_CONF_HTTP_URL']
190-
191-
JavaBuildpack::Util::Cache::InternetAvailability.instance.available(
192-
true, 'The AppDynamics remote configuration download location is always accessible'
193-
) do
194-
agent_root = @application.environment['APPD_CONF_HTTP_URL'].chomp('/') + '/java/'
195-
@logger.info { "Downloading override configuration files from #{agent_root}" }
196-
CONFIG_FILES.each do |conf_file|
197-
uri = URI(agent_root + conf_file)
198-
199-
# `download()` uses retries with exponential backoff which is expensive
200-
# for situations like 404 File not Found. Also, `download()` doesn't expose
201-
# an api to disable retries, which makes this check necessary to prevent
202-
# long install times.
203-
next unless check_if_resource_exists(uri, conf_file)
204-
205-
download(false, uri.to_s) do |file|
206-
Dir.glob(@droplet.sandbox + 'ver*') do |target_directory|
207-
FileUtils.cp_r file, target_directory + '/conf/' + conf_file
208-
end
209-
end
210-
end
211-
end
212-
end
213-
214159
# Check for configuration files locally. If found, copy to conf dir under each ver* dir
215160
# @return [Void]
216161
def override_default_config_local
@@ -226,9 +171,13 @@ def override_default_config_local
226171

227172
next unless File.file?(conf_file_path)
228173

229-
Dir.glob(@droplet.sandbox + 'ver*') do |target_directory|
230-
FileUtils.cp_r conf_file_path, target_directory + '/conf/' + conf_file
231-
end
174+
save_cfg_file(conf_file_path, conf_file)
175+
end
176+
end
177+
178+
def save_cfg_file(file, conf_file)
179+
Dir.glob(@droplet.sandbox + 'ver*') do |target_directory|
180+
FileUtils.cp_r file, target_directory + '/conf/' + conf_file
232181
end
233182
end
234183
end

lib/java_buildpack/framework/luna_security_provider.rb

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
require 'fileutils'
1919
require 'java_buildpack/component/versioned_dependency_component'
2020
require 'java_buildpack/framework'
21+
require 'java_buildpack/util/external_config'
2122
require 'java_buildpack/util/qualify_path'
2223

2324
module JavaBuildpack
@@ -26,6 +27,18 @@ module Framework
2627
# Encapsulates the functionality for enabling zero-touch Safenet Luna HSM Java Security Provider support.
2728
class LunaSecurityProvider < JavaBuildpack::Component::VersionedDependencyComponent
2829
include JavaBuildpack::Util
30+
include JavaBuildpack::Util::ExternalConfig
31+
32+
# Full list of configuration files that can be downloaded remotely
33+
CONFIG_FILES = %w[Chrystoki.conf server-certificates.pem].freeze
34+
35+
# Prefix to be used with external configuration environment variable
36+
CONFIG_PREFIX = 'LUNA'
37+
38+
def initialize(context)
39+
super(context)
40+
@logger = JavaBuildpack::Logging::LoggerFactory.instance.get_logger LunaSecurityProvider
41+
end
2942

3043
# (see JavaBuildpack::Component::BaseComponent#compile)
3144
def compile
@@ -36,10 +49,11 @@ def compile
3649
@droplet.security_providers << 'com.safenetinc.luna.provider.LunaProvider'
3750
@droplet.root_libraries << luna_provider_jar if @droplet.java_home.java_9_or_later?
3851

39-
credentials = @application.services.find_service(FILTER, 'client', 'servers', 'groups')['credentials']
40-
write_client credentials['client']
41-
write_servers credentials['servers']
42-
write_configuration credentials['servers'], credentials['groups']
52+
write_credentials
53+
54+
override_default_config_remote do |file, conf_file|
55+
FileUtils.cp_r file, @droplet.sandbox + conf_file
56+
end
4357
end
4458

4559
# (see JavaBuildpack::Component::BaseComponent#release)
@@ -57,11 +71,27 @@ def release
5771

5872
# (see JavaBuildpack::Component::VersionedDependencyComponent#supports?)
5973
def supports?
60-
@application.services.one_service? FILTER, 'client', 'servers', 'groups'
74+
@application.services.one_service?(FILTER, 'client', 'servers', 'groups') ||
75+
@application.services.one_service?(FILTER, 'client', 'servers') ||
76+
@application.services.one_service?(FILTER, 'client')
6177
end
6278

6379
private
6480

81+
def write_credentials
82+
service = @application.services.find_service(FILTER, 'client', 'servers', 'groups') ||
83+
@application.services.find_service(FILTER, 'client', 'servers') ||
84+
@application.services.find_service(FILTER, 'client')
85+
credentials = service['credentials']
86+
87+
write_client credentials['client'] if credentials.key? 'client'
88+
write_servers credentials['servers'] if credentials.key? 'servers'
89+
90+
return unless credentials.key?('servers') && credentials.key?('groups')
91+
92+
write_configuration credentials['servers'], credentials['groups']
93+
end
94+
6595
FILTER = /luna/.freeze
6696

6797
private_constant :FILTER
@@ -254,6 +284,11 @@ def write_servers(servers)
254284
end
255285
end
256286

287+
# Overrides method from ExternalConfig module & provides root URL for where external configuration will be located
288+
def external_config_root
289+
@application.environment["#{CONFIG_PREFIX}_CONF_HTTP_URL"].chomp('/') + '/'
290+
end
291+
257292
end
258293
end
259294
end

0 commit comments

Comments
 (0)