Evident Security Platform SDK
A Ruby interface for calling the Evident.io API.
This Readme is for the V2 version of the ESP SDK. For V1 information, see the V1 WIKI.
Installation
Add this line to your application's Gemfile:
gem 'esp_sdk'
And then execute:
bundle
Or install it yourself as:
gem install esp_sdk
Configuration
Set your HMAC security keys:
You must set your access_key_id and your secret_access_key.
You can set these directly:
ESP.access_key_id = <your key>
ESP.secret_access_key = <your secret key>
or with environment variables:
ENV['ESP_ACCESS_KEY_ID'] = <you key>
ENV['ESP_SECRET_ACCESS_KEY'] = <your secret key>
or, if in a Rails application, you can use the configure block in an initializer:
ESP.configure do |config|
config.access_key_id = <your key>
config.secret_access_key = <your secret key>
end
Get your HMAC keys from the Evident.io website, esp.evident.io
Appliance Users
Users of Evident.io's AWS marketplace appliance will need to set the host for their appliance instance. You can set this directly:
ESP.host = <host for appliance instance>
or, if in a Rails application, you can use the configure block in an initializer:
ESP.configure do |config|
config.host = <host for appliance instance>
end
Alternatively, the site can also be set with an environment variable.
export ESP_HOST=<host for appliance instance>
Usage
Everything is an Object
The Evident.io SDK uses Active Resource, so the DSL acts very much like Active Record providing by default, the standard CRUD actions
find, all, create, update, destroy, only instead of a database as the data store, it makes calls to the Evident.io API. Not all
methods are available for all ESP objects. See the documentation to see all the methods
available for each object.
So, for instance, to get a report by ID:
espsdk:003:0> report = ESP::Report.find(234)
And to get the alerts for that report:
espsdk:003:0> alerts = report.alerts
For objects that are creatable, updatable, and destroyable, you make the exact same calls you would expect to use with Active Record.
espsdk:003:0> team = ESP::Team.create(name: 'MyTeam', organization_id: 452, sub_organization_id: 599)
espsdk:003:0> team.name = 'NewName'
espsdk:003:0> team.save
espsdk:003:0> team.destroy
Use the attributes method to get a list of all available attributes that each object has.
espsdk:003:0> team = ESP::Team.find(1)
espsdk:004:0> team.attributes
# => {
# => "id" => "1",
# => "type" => "teams",
# => "relationships" => #<ESP::Team::Relationships:0x007fdf1b451710 @attributes={"sub_organization"=>#<ESP::SubOrganization:0x007fdf1b450d60 @attributes={"data"=>#<ESP::SubOrganization::Data:0x007fdf1b450978 @attributes={"id"=>"1", "type"=>"sub_organizations"}, @prefix_options={}, @persisted=true>, "links"=>#<ESP::SubOrganization::Links:0x007fdf1b4503b0 @attributes={"related"=>"http://localhost:3000/api/v2/sub_organizations/1.json"}, @prefix_options={}, @persisted=true>}, @prefix_options={}, @persisted=true>, "organization"=>#<ESP::Organization:0x007fdf1b45bbc0 @attributes={"data"=>#<ESP::Organization::Data:0x007fdf1b45b7d8 @attributes={"id"=>"1", "type"=>"organizations"}, @prefix_options={}, @persisted=true>, "links"=>#<ESP::Organization::Links:0x007fdf1b45b210 @attributes={"related"=>"http://localhost:3000/api/v2/organizations/1.json"}, @prefix_options={}, @persisted=true>}, @prefix_options={}, @persisted=true>, "external_accounts"=>#<ESP::Team::Relationships::ExternalAccounts:0x007fdf1b45a040 @attributes={"data"=>[#<ESP::Team::Relationships::ExternalAccounts::Datum:0x007fdf1b458830 @attributes={"id"=>"1", "type"=>"external_accounts"}, @prefix_options={}, @persisted=true>], "links"=>#<ESP::Team::Links:0x007fdf1b463e38 @attributes={"related"=>"http://localhost:3000/api/v2/external_accounts.json"}, @prefix_options={}, @persisted=true>}, @prefix_options={}, @persisted=true>}, @prefix_options={}, @persisted=true>,
# => "name" => "Default Team",
# => "created_at" => "2015-09-23T14:37:48.000Z",
# => "updated_at" => "2015-09-23T14:37:48.000Z",
# => "sub_organization_id" => "1",
# => "organization_id" => "1",
# => "external_account_ids" => [
# => [0] "1"
# => ]
# => }
Errors
Active Resource objects have an errors collection, just like Active Record objects. If the API call returns a non fatal response, like validation issues, you can check the errors object to see what went wrong.
espsdk:003:0> t = ESP::Team.create(name: '')
espsdk:003:0> t.errors
# => {
# => :base => [
# => [0] "Organization can't be blank",
# => [1] "Sub organization can't be blank"
# => ],
# => :name => [
# => [0] "can't be blank"
# => ]
# => }
The errors will be in the :base key rather than the corresponding attribute key, since we have not defined a schema for the objects in order to stay more loosely coupled to the API.
espsdk:003:0> t.errors.
# => [
# => [0] "Organization can't be blank",
# => [1] "Sub organization can't be blank",
# => [2] "Name can't be blank"
# => ]
When an error is thrown, you can rescue the error and check the error message:
espsdk:003:0> c = ESP::CustomSignature.find(435)
espsdk:003:0> c.run!(external_account_id: 999)
# => ActiveResource::ResourceInvalid: Failed. Response code = 422. Response message = Couldn't find ExternalAccount.
# => from /Users/kevintyll/evident/esp_sdk/lib/esp/resources/custom_signature.rb:23:in `run!'
begin
c.run!(external_account_id: 999)
rescue ActiveResource::ResourceInvalid => e
puts e.
end
# => Failed. Response code = 422. Response message = Couldn't find ExternalAccount.
All non get requests have a corresponding ! version of the method. These methods will throw an error rather than swallow
the error and return an object with the errors object populated. For example, the run and run! methods on CustomSignature.
Pagination
Evident.io API endpoints that return a collection of objects allows for paging and only returns a limited number of items at a time.
The Evident.io SDK returns an ESP::PaginatedCollection object that provides methods for paginating through the collection.
The methods with a ! suffix update the object, methods without the ! suffix return a new page object preserving the
original object.
espsdk:004:0> alerts = ESP::Alert.for_report(345)
espsdk:004:0> alerts.current_page_number # => "1"
espsdk:004:0> page2 = alerts.next_page
espsdk:004:0> alerts.current_page_number # => "1"
espsdk:004:0> page2.current_page_number # => "2"
espsdk:004:0> page2.previous_page!
espsdk:004:0> page2.current_page_number # => "1"
espsdk:004:0> alerts.last_page!
espsdk:004:0> alerts.current_page_number # => "25"
espsdk:004:0> page4 = alerts.page(4)
espsdk:004:0> alerts.current_page_number # => "25"
espsdk:004:0> page4.current_page_number # => "4"
Associated Objects
Most of the objects in the Evident.io SDK have a corresponding API call associated with it. That means if you call an object's association, then that will make another API call. For example:
espsdk:004:0> external_account = ESP::ExternalAccount.find(3)
espsdk:004:0> organization = external_account.organization
espsdk:004:0> sub_organization = external_account.sub_organization
espsdk:004:0> team = external_account.team
The above code will make 4 calls to the Evident.io API. 1 each for the external account, organization, sub_organization and team. The JSON API Specification, which the Evident.io API tries to follow, provides a means for returning nested objects in a single call. With the SDK, that can be done by providing a comma separated string of the relations wanted in an +include+ option.
espsdk:004:0> external_account = ESP::ExternalAccount.find(3, include: 'organization,sub_orgnanization,team')
With that call, organization, sub_organization and team will all come back in the response, and calling, external_account.organization,
external_account.sub_organization and external_account.team, will not make another API call. Most objects' find method accepts the
+include+ option.
See the Documentation for all the pagination methods available.
Available Objects
- ESP::Alert
- ESP::CloudTrailEvent
- ESP::ContactRequest
- ESP::CustomSignature
- ESP::Dashboard
- ESP::ExternalAccount
- ESP::Organization
- ESP::Region
- ESP::Report
- ESP::Service
- ESP::Signature
- ESP::Stat
- ESP::SubOrganization
- ESP::Suppression
- ESP::Suppression::Region
- ESP::Suppression::Signature
- ESP::Suppression::UniqueIdentifier
- ESP::Tag
- ESP::Team
- ESP::User
Console
The Evident.io SDK gem also provides an IRB console you can use if not using it in a Rails app. Run it with bin/esp_console
Contributing
- Fork it ( https://github.com/[my-github-username]/esp_sdk/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request