11 EDQ暗号化の構成

EDQの暗号化フレームワークでは、この章で説明するように、OCIボールトおよびスクリプトの実装とともにプラガブル・モジュールがサポートされるようになりました。

強化されたEDQ暗号化の概要

セキュリティを強化するために、EDQ構成に格納されている特定の情報が暗号化されます。

  • director.propertiesのデータベース・パスワード(オプション、Tomcatのみ)

  • データ・ストアのパスワード

  • 格納されている資格証明

  • Webプッシュ通知Vapid秘密キー

バージョン12.2.1.4.3までのEDQでは、暗号化はECBモードのAES暗号を使用し、PKCS5Paddingを指定して実行されます。最初の起動時に、新しいランダム・キーが生成されて格納されます。Tomcatでは、キーはファイルlocalhome/kfileに格納され、WebLogicではキーはFMWキー・ストアに格納されます。

この実装には、次のような制限があります。
  • デフォルトのAESキー・サイズ(128ビット)が使用されます。セキュリティを強化するには、256ビットを使用する必要があります。

  • ECB暗号モードでは初期化ベクトル(IV)を使用しないため、同じ文字列を暗号化すると常に同じ結果が生成されます。そのため、攻撃者が暗号化された値を確認できれば、容易にパスワードを推測できます。

  • Tomcatでは、システムのどのユーザーでもキー・ファイルを読み取ることができます。

  • 既存のスキーマを使用して新しいインストールを作成すると、新しいキー・ファイルが生成され、データベースにあって暗号化されている既存のデータはリカバリできません(この問題はOCIマーケットプレイス・イメージでも共通です)。

バージョン12.2.2.1.4.4以降のEDQでは、暗号化および復号化はプラガブル・セキュリティ・モジュールによって処理されます。モジュールは、新しいプロパティ・ファイルlocalhome/security/module.propertiesによって構成されます。これには、モジュール・タイプを定義するタイプ・プロパティが含まれている必要があります。次のタイプがサポートされています。
  • legacy - module.propertiesが存在しない場合にデフォルトで使用される現在のメカニズム。
  • default - セキュリティが向上したレガシーモジュールのリファクタリング。
  • ocivault - OCIボールトに格納されているキーを使用します。暗号化と復号化は、ボールト暗号化エンドポイントのコールによって実行されます。キーがボールトから離れることはないため、HSMまたはソフトウェア保護モードを使用できます。セキュリティを強化するためにキーをローテーションできます。データの暗号化するときにキー・バージョンを使用する復号化操作です。ボールト・シークレットを使用して資格証明ストアとして機能するように構成できます。
  • script - 暗号化および復号化操作を実行するようにJavaScriptスクリプトを構成できます。これは、AWS Key Management Service (KMS)やGCP Cloud Key Management Serviceなどの追加のキー・フレームワークをサポートするために使用できます。このモジュールは、AWSやGCP Secrets Managerなどの外部サービスを使用して資格証明ストアとして機能するように構成することもできます。
  • custom - カスタムJavaコード。詳細は、「カスタムJava暗号化および資格証明ストア・モジュールの作成」を参照してください。
新規インストールではデフォルト・モジュールが使用されます。以前のバージョンから移行されたインストールでは、引き続きレガシー・モジュールが使用されます。

デフォルト・セキュリティ・モジュール

新しいデフォルト・セキュリティ・モジュールは、レガシー実装に似ていますが、次の点で機能が強化されています。
  • AESはランダムな初期化ベクトルを利用してGCMモードで使用されるため、同じデータを暗号化すると毎回異なる結果が返されます。
  • 可能な場合は256ビット・キーが使用されます。
  • Tomcatでは、キーはモード600 (-rw-------)に設定されたファイルlocalhome/masterkeyに格納されます。

Ocivaultセキュリティ・モジュール

ocivaultセキュリティ・モジュール・タイプでは、OCIボールトに格納されているキーが使用されます。OCI APIのコールの認証では、プラットフォーム資格証明か、外部プロパティで構成された資格証明のいずれかを使用します。格納された資格証明はここでは使用できません。このモジュールを使用すると、起動時にEDQデータベース・スキーマのパスワードを復号化できるためです。

module.propertiesの型には、次の追加プロパティが使用されます。

表11-1 Ocivaultセキュリティ・モジュールのプロパティ

プロパティ 説明

vault

ボールト名またはOCID (必須)。

key

キー名またはOCID (必須)。

region

OCIリージョン名。省略した場合は、EDQインスタンスのリージョンが使用されます。

compartmentid

ボールト・コンパートメントのOCID。ボールトまたはキーがOCIDで指定されていない場合に使用されます。省略した場合は、EDQインスタンスのコンパートメントが使用されます。

secrets.vault

シークレット問合せのボールト名またはOCID。省略した場合は、キー・ボールトが使用されます。

secrets.encrypt

ボールト・キーを使用してシークレット値を暗号化する場合、trueに設定します。シークレット値はOCIコンソールで表示できるため、コンソールに表示しないためには暗号化する必要があります。

secrets

ボールト・シークレットを使用した資格証明の取得をサポートするには、trueに設定します。

auth.X

OCI APIコールのオーセンティケータに渡される追加プロパティ。たとえば、auth.profileを設定して、~/.oci/configからプロファイルに名前を付けます。

OCIモジュールの主なユース・ケースは、OCI APIコールの認証にプラットフォーム資格証明を使用できるコンピュート・インスタンスで使用する場合です。OCIダイナミック・グループが必要な権限を示している場合、追加の構成は必要ありません。

シークレット・ストレージ

モジュールでシークレットが使用可能になっている場合、外部統合の資格証明は、EDQ構成ファイルではなくボールトに格納できます。例としては、JMSブローカ接続、SMTP認証、LDAP資格証明があります。

シークレットを使用して資格証明を指定するには、ユーザー名およびパスワードのプロパティを次のように置き換えます。

cred.secret = secretname

この値のシークレット・ボールトは、次に示すように、usernameおよびpassword属性を含むJSON文字列である必要があります。

{ "username": "user1", "password": "mysecret2" }

モジュールのデフォルトのシークレット暗号化設定をオーバーライドするには、次の行を使用します。

cred.secret.encrypt = true | false

プレーンでユーザー名を指定し、ボールトからパスワードを取得するには、次の行を使用します。

cred.secret.username = username

こうすると、ボールトのシークレット値はパスワードのみになります。

ユーザー名が必要ない場合は、次の行を追加します。

cred.secret.passwordonly = true

こうすると、ボールトのシークレット値はパスワードのみになります。

OCI Vaultのmodule.properties構成の例

ローカル・コンパートメントとリージョンでプラットフォーム資格証明を使用する例:


type            = ocivault
vault           = edqvault
key             = key1
secrets         = true
secrets.encrypt = true

~/.oci/configからの資格証明でリモート・ボールトを使用する例:


type            = ocivault
auth.profile    = default
region          = us-phoenix-1
compartmentid   = compartmentid
vault           = edqvault
key             = key1
secrets         = true

スクリプト・セキュリティ・モジュール

スクリプト・セキュリティ・モジュールのモジュール定義には、スクリプト・プロパティとしてスクリプト・ファイルの名前が含まれている必要があります。ファイルが絶対でない場合、EDQローカル構成ディレクトリを基準として検索されます。このスクリプトは、次の表に示す関数を定義します。

表11-2 スクリプト・セキュリティ・モジュールの関数

関数 必須 説明

init(props)

いいえ

モジュールを初期化します。引数は、module.propertiesのプロパティを含むオブジェクトです。

encrypt(plain)

はい

プレーン・テキストを暗号化します。引数と結果はArrayBuffersです。

decrypt(plain)

はい

暗号文を復号化します。引数と結果はArrayBuffersです。

getCredentials(props)

いいえ

シークレット・ストアから資格証明を取得します。properties引数には、EDQ構成からのcred.*設定が含まれます。

init関数に渡されるプロパティには、「encryption」に設定された type値が含まれます。そのため、セキュリティ・モジュールおよび資格証明ストアと同じスクリプトを使用できます。

base64関連

外部暗号化APIでは、プレーン・テキストおよび暗号テキストにbase64エンコーディングが必要です。EDQスクリプトでは、次のbase64サポート関数を使用できます。


var encoder = BASE64.getEncoder()
var enc     = encoder.encode(bytes)                 // Encode an ArrayBuffer to base64 string
var enc2    = encoder.encodeFromString(str)         // Encode a string to base 64 string
 
var urlenc  = BASE64.getUrlEncoder()                // Encoder using URL-safe alphabet
var mimeenc = BASE64.getMimeEncoder()               // Encoder with MIME line splitting
vat nopad   = BASE64.getEncoder().withoutPadding()  // Encoder which does not use = padding
 
var decoder = BASE64.getDecoder()
var dec     = decoder.decode(string)                // Decode a base64 string to ArrayBuffer
var dec2    = encoder.decodeToString(str)           // Decode a base 64 string to a string
 
var urldec  = BASE64.getUrlEncoder()                // Decoder using URL-safe alphabet
var mimdec  = BASE64.getMimeEncoder()               // Decoder with MIME line splitting

サンプル・スクリプト

AWSキーおよびシークレット管理フレームワークを使用する例

module.properties


type         = script
keyid        = alias/rde1
region       = eu-west-1
script       = awsenc.js
secrets      = true
auth.profile = myprofile

awsenc.js


// Script security module sample for AWS KMS and secrets manager
// =============================================================
//
// Required properties:
//
//      region          AWS region
//      keyid           KMS keyid or alias/name
//
// Optional:
//
//      secrets         Set to true for secrets support
//
// Configure proxy server with https.proxyHost and https.proxyPort properties
 
addLibrary("http")
addLibrary("logging")
 
var client
var secclient
var encoder = BASE64.getEncoder()
var decoder = BASE64.getDecoder()
var kmsurl
var keyid
var secrets   = false
var secretenc = false
 
function init(props) {
 
  // Authentication properties
 
  var aprops = Object.keys(props).filter(k => k.startsWith("auth.")).reduce((o, k) => (o[k.substring(5)] = props[k], o), {})
 
  // Client for KMS
 
  client = HTTP.builder().withAWSAuthentication(aprops).build();
 
  // Properties
 
  var region   = props.region
 
  keyid = props.keyid
 
  if (!region || !keyid) {
    throw "awsenc: region or key not specified"
  }
 
  kmsurl  = "https://kms." + region + ".amazonaws.com"
 
  // Secrets handling
 
  secrets = props.secrets == "true"
   
  if (secrets) {
 
    // URL and client for secret queries
 
    securl    = "https://secretsmanager." + region + ".amazonaws.com"
    secclient = HTTP.builder().withAWSAuthentication(aprops).build();
  }
}
 
function encrypt(plain) {
  var req = client.requestbuilder().header("X-Amz-Target", "TrentService.Encrypt").build();
  var res = req.post(kmsurl, JSON.stringify({KeyId: keyid, Plaintext: encoder.encode(plain)}), "application/x-amz-json-1.1")
 
  return decoder.decode(JSON.parse(res.data).CiphertextBlob)
}
 
function decrypt(ctext) {
  var req = client.requestbuilder().header("X-Amz-Target", "TrentService.Decrypt").build();
  var res  = req.post(kmsurl, JSON.stringify({keyId: keyid, CiphertextBlob: encoder.encode(ctext)}), "application/x-amz-json-1.1")
 
  return decoder.decode(JSON.parse(res.data).Plaintext)
}
 
function getCredentials(props) {
  if (secrets) {
    var s = props.secret
 
    if (s) {
      var req = secclient.requestbuilder().failonerror(false).header("X-Amz-Target", "secretsmanager.GetSecretValue").build()
      var res = req.post(securl, JSON.stringify({SecretId: s}), "application/x-amz-json-1.1")
 
      if (res.code != 200) {
        logger.log(Level.WARNING, "AWS secrets manager call failed with code {0}", res.code)
      } else {
        var obj = JSON.parse(res.data)
        var str = obj.SecretString || decoder.decodeToString(obj.SecretBinary)
         
        if (props["secret.passwordonly"] == "true") {
          return {username: "", password: str}
        } else {
          var val = JSON.parse(str)
          return {username: val.username, password: val.password}
        }
      }
    }
  }
 
  return null
}

GCPキーおよびシークレット・フレームワークを使用する例

module.properties


type       = script
script     = gcpenc.js
project    = green-wombat-4252311
keyfile    = /opt/edq/gcp-encrypt.json
location   = europe-west2
keyring    = rde
key        = rde1
secrets    = true
seckeyfile = /opt/edq/gcp-secrets.json

gcpenc.js


// Script security module sample for GCP KMS and secrets manager
// =============================================================
//
// Required properties:
//
//      project         GCP project name
//      location        Key location (such as europe-west2)
//      keyring         Keyring name
//      key             Key name
//      keyfile         Service account key file location
//
// Optional:
//
//      version         Key version name
//
// Configure proxy server with https.proxyHost and https.proxyPort properties
 
addLibrary("http")
addLibrary("logging")
 
var client
var encoder = BASE64.getEncoder()
var decoder = BASE64.getDecoder()
var decurl
var encurl
var secrets   = false
 
function init(props) {
 
  // Need:
  //
  // project
  // location
  // keyring
  // key
  // keyfile
  //
  // Optional:
  //
  // version
 
  if (!props.project || !props.location || !props.keyring || !props.key || !props.keyfile) {
     throw "gcpenc: missing properties"
  }
 
  var project = props.project
  var location = props.location
 
  var base = "https://cloudkms.googleapis.com/v1"
        + "/projects/"   + props.project
        + "/locations/"  + props.location
        + "/keyRings/"   + props.keyring
        + "/cryptoKeys/" + props.key
 
  decurl = base + ":decrypt"
  encurl = base
 
  if (props.version) {
    encurl += "/cryptoKeyVersions/" + props.version
  }
 
  encurl += ":encrypt"
 
  // Client for KMS
 
  client = HTTP.builder().withAuthentication("GCP", {keyfile: props.keyfile, claim_scope: "https://www.googleapis.com/auth/cloud-platform"}).build();
 
  secrets = props.secrets == "true"
   
  if (secrets) {
 
    // URL and client for secret queries
 
    securl = "https://secretmanager.googleapis.com/v1/projects/" + props.project + "/secrets/"
  }
}
 
function encrypt(plain) {
  var req = client.requestbuilder().build();
  var res = req.post(encurl, JSON.stringify({"plaintext": encoder.encode(plain)}))
   
  return decoder.decode(JSON.parse(res.data).ciphertext)
}
 
function decrypt(ctext) {
  var req = client.requestbuilder().build();
  var res  = req.post(decurl, JSON.stringify({ciphertext: encoder.encode(ctext)}))
 
  return decoder.decode(JSON.parse(res.data).plaintext)
}
 
function getCredentials(props) {
  if (secrets) {
    var s = props.secret
 
    if (s) {
      var url = securl + s + "/versions/latest:access"
      var req = client.requestbuilder().failonerror(false).build()
      var res = req.get(url)
 
      if (res.code != 200) {
        logger.log(Level.WARNING, "GCP secrets manager call failed with code {0}", res.code)
      } else {
        var obj = JSON.parse(res.data)
        var str = decoder.decodeToString(obj.payload.data)
         
        if (props["secret.passwordonly"] == "true") {
          return {username: "", password: str}
        } else {
          var val = JSON.parse(str)
          return {username: val.username, password: val.password}
        }
      }
    }
  }
 
  return null
}

暗号化の移行

既存のシステムでセキュリティ・モジュールが置換または再構成されると、暗号化されたデータは使用できなくなります。システムが新規インストールで、director.propertiesで暗号化が使用されていない場合、これは問題ではありません。既存の暗号化データがある場合は、移行REST APIを使用して新しいセキュリティ・モジュールを定義できます。

新しいシステム管理RESTエンドポイントが2つあります。

/edq/admin/security/migrateencryptionにPOST

ペイロードは、次の構造を持つJSONオブジェクトです。


{ "type" : "moduletype",
  "properties": {
 	... other settings for the module ...
  }
}
移行プロセスには次のステップが含まれます。
  1. ペイロードの定義を使用して、新しいセキュリティが作成および初期化されます。
  2. 既存の暗号化データは、現在のモジュールを使用して復号化され、新しいモジュールを使用して暗号化されます。
  3. 前述のステップが成功すると、新しいモジュールが現在のモジュールを置き換え、新しい定義でmodule.propertiesが書き込まれます。

移行コールの結果は、更新された項目を要約したレポートです。復号化できなかった項目があれば一覧表示されます。

URLに問合せパラメータ?dryrun=trueが含まれている場合、新しいモジュールが作成され、既存のデータの復号化がテストされますが、更新は行われません。

リモートOCI Vaultへの移行のペイロードの例


{ "type" : "ocivault",
  "properties": {
    "auth.profile"    : "default",
    "vault"           : "rde",
    "key"             : "rtest",
    "compartmentid"   : "compartmentid",
    "region"          : "us-phoenix-1",
    "secrets"         : true,
    "secrets.encrypt" : true
  }
}

/etc/admin/security/rotateencryptionへのPOST

ペイロードは空のJSONオブジェクトです。既存の暗号化データは、現在のセキュリティ・モジュールを使用して復号化され、同じモジュールを使用して暗号化されます。古いバージョンを削除できるように、このコールは、新しいバージョンの作成後にボールト・キーで使用できます。

コールの結果は、移行コールのサマリーです。

URLに問合せパラメータ?dryrun=trueが含まれている場合、既存のデータの復号化がテストされますが、更新は行われません。

暗号化データを失わずに新しいOCIインスタンスで既存のスキーマを使用

新しいOCIインスタンスを作成しても、「既存のスキーマの使用」オプションを選択すると、新しいインスタンスはレガシー(またはデフォルト)のセキュリティ・モジュールで始まります。新しい秘密キーが作成され、既存の暗号化データにはアクセスできなくなります。データを保持するステップは、次のとおりです。

  1. 古いシステムを停止する前に、外部暗号化メカニズム(OCIボールトまたはAWS)を使用していることを確認してください。
  2. 新規システムを作成して設定します。
  3. 暗号化の移行を実行して、新しいシステムで外部モジュールを設定します。既存のデータの復号化は失敗します。現在のモジュールは異なるが、移行は完了後しているからです。暗号化されたデータは再度使用できます。

プラガブル資格証明ストアの構成

EDQ構成で使用されるユーザー名とパスワード資格証明は通常、プロパティ・ファイルで定義されます。

次に例を示します:
  • director.propertiesのデータベース・スキーマのパスワード
  • 「バケット」ファイルでのJMSブローカ認証
  • mail.propertiesでのSMTP認証
  • login.propertiesでのLDAP認証

WebLogicでインスタンスを実行すると、資格証明はFMW資格証明ストア・フレームワークに格納されます。バージョン12.2.1.4.4以降のEDQの暗号化モジュール・メカニズムでは、セキュリティ・モジュールを資格証明ストアとして機能させることができますが、これは追加ストアの定義をサポートしていません。たとえば、ローカル暗号化メカニズムを使用して、OCI VaultsやAWS Secrets Managerなどの外部ストアから資格証明を取得することはできません。

追加の資格証明ストアの構成

バージョン12.2.1.4.4以降のEDQでは、追加の資格証明ストアを定義できるように暗号化モジュールが拡張されています。ストアは、localhome/security/credstoresディレクトリにプロパティ・ファイルを追加することによって構成されます。各プロパティ・ファイルには、ストアタイプとそれに固有の追加設定とを定義する typeプロパティが含まれている必要があります。次のタイプがサポートされています。

  • ocivault - 資格証明はシークレットとしてOCIボールトに格納され、値キーを使用して暗号化できます。
  • script - JavaScriptスクリプトは、AWSやGCPシークレット・マネージャなどの外部サービスにコールアウトするように構成できます。
  • custom - カスタムJavaクラス。

格納される資格証明は、関連付けられたファイル名のアルファベット順に問い合せられます。

Ocivault資格証明ストア

ocivaultセキュリティ・モジュール・タイプは、OCIボールトに格納されているシークレットを問い合せます。OCI APIのコールの認証では、プラットフォーム資格証明か、外部プロパティで構成された資格証明のいずれかを使用します。格納された資格証明はここでは使用できません。このモジュールを使用すると、起動時にEDQデータベース・スキーマのパスワードを問い合せることができるためです。

このタイプでは、次の追加プロパティが使用されます。

表11-3 Ocivault資格証明ストア

プロパティ 説明

vault

ボールト名またはOCID (必須)。

secrets.encrypt

ボールトからのキーを使用してシークレット値を暗号化する場合、trueに設定します。シークレット値はOCIコンソールで表示できるため、コンソールに表示しないためには暗号化する必要があります。

キー

キー名またはOCID (secrets.encryptがtrueの場合は必須)。

region

OCIリージョン名。省略した場合は、EDQインスタンスのリージョンが使用されます。

compartmentid

ボールト・コンパートメントのOCID。ボールトまたはキーがOCIDで指定されていない場合に使用されます。省略した場合は、EDQインスタンスのコンパートメントが使用されます。

auth.X

OCI APIコールのオーセンティケータに渡される追加プロパティ。たとえば、auth.profileを設定して、~/.oci/configからプロファイルに名前を付けます。

OCIの主なユース・ケースは、OCI APIコールの認証にプラットフォーム資格証明を使用できるコンピュート・インスタンスで使用する場合です。OCIダイナミック・グループが必要な権限を示している場合、追加の構成は必要ありません。

シークレットの使用

ボールト・シークレットを使用して資格証明を指定するには、ユーザー名およびパスワードのプロパティを次のように置き換えます。

cred.secret = secretname

この値のシークレット・ボールトは、次に示すように、usernameおよびpassword属性を含むJSON文字列である必要があります。

{ "username": "user1", "password": "mysecret2" }

モジュールのデフォルトのシークレット暗号化設定をオーバーライドするには、次の行を使用します。

cred.secret.encrypt = true | false

プレーンでユーザー名を指定し、ボールトからパスワードを取得するには、次の行を使用します。

cred.secret.username = username

こうすると、ボールトのシークレット値はパスワードのみになります。

ユーザー名が必要ない場合は、次の行を追加します。

cred.secret.passwordonly = true

こうすると、ボールトのシークレット値はパスワードのみになります。

oci.properties


type            = ocivault
secrets.encrypt = true
vault           = vault1
key             = rtest
compartmentid   = ocid1.compartment.oc1..aaaaaaaaeq2s...
region          = us-phoenix-1

スクリプト資格証明ストア

スクリプト資格証明ストアのプロパティには、スクリプト・ファイルの名前としてscriptプロパティが含まれている必要があります。ファイルが絶対でない場合、EDQローカル構成ディレクトリを基準として検索されます。このスクリプトは、次の機能を定義します。

表11-4 スクリプト資格証明ストア

関数 必須 説明

init(props)

いいえ

モジュールを初期化します。引数は、プロパティ・ファイルのプロパティを含むオブジェクトです。

getCredentials(props)

はい

シークレット・ストアから資格証明を取得します。properties引数には、EDQ構成からのcred.*設定が含まれます。

init関数に渡されるプロパティには、「credentials」に設定された type値が含まれています。そのため、セキュリティ・モジュールおよび資格証明ストアと同じスクリプトを使用できます。

AWSシークレット管理フレームワークを使用する例

base64サポート関数の詳細は、「強化されたEDQ暗号化の概要」を参照してください。

aws.properties


type         = script
region       = eu-west-1
script       = awscreds.js
auth.profile = myprofile

awscreds.js


// Script credentials module sample for AWS secrets manager
// =========================================================
//
// Required properties:
//
//      region          AWS region
//
// Configure proxy server with https.proxyHost and https.proxyPort properties
 
addLibrary("http")
addLibrary("logging")
 
var secclient
var encoder = BASE64.getEncoder()
var decoder = BASE64.getDecoder()
 
function init(props) {
 
  // Authentication properties
 
  var aprops = Object.keys(props).filter(k => k.startsWith("auth.")).reduce((o, k) => (o[k.substring(5)] = props[k], o), {})
 
  // Properties
 
  var region   = props.region
 
  if (!region) {
    throw "awscreds: region not specified"
  }
 
  // URL and client for secret queries
 
  securl    = "https://secretsmanager." + region + ".amazonaws.com"
  secclient = HTTP.builder().withAWSAuthentication(aprops).build();
}
 
function getCredentials(props) {
  var s = props.secret
 
  if (s) {
    var req = secclient.requestbuilder().failonerror(false).header("X-Amz-Target", "secretsmanager.GetSecretValue").build()
    var res = req.post(securl, JSON.stringify({SecretId: s}), "application/x-amz-json-1.1")
 
    // Error 400 can mean secret not found, so don't report it
 
    if (res.code != 200) {
      if (res.code != 400) {
        logger.log(Level.WARNING, "AWS secrets manager call failed with code {0}", res.code)
      }
    } else {
      var obj = JSON.parse(res.data)
      var str = obj.SecretString || decoder.decodeToString(obj.SecretBinary)
 
      if (props["secret.passwordonly"] == "true" || props["secret.username"]) {
        return {username: props["secret.username"] || "", password: str}
      } else {
        var val = JSON.parse(str)
        return {username: val.username, password: val.password}
      }
    }
  }
 
  return null
}

カスタムJava暗号化および資格証明ストア・モジュールの作成

バージョン12.2.1.4.4および14.1.2.0.0のEDQでは、暗号化および資格証明の検索用のプラガブル・モジュールがサポートされています。次の項では、カスタムJavaクラスを使用してモジュールを実装する方法について説明します。このカスタムJavaクラスは、ネイティブ・コードが必要という理由で一部のセキュリティ・ストアと対話するスクリプトを作成できない場合に必要になります。

カスタム・モジュールは、次に示すように定義されます。


type  = custom
class = java class name
次のステップを実行して、カスタム・モジュールを作成します。
  1. 必要なインタフェースを実装するJavaクラスを作成します。
  2. クラスパスでinstalldir/buildjars/customsecuritymodules.jarを使用してクラスをコンパイルします。
  3. localhome/security/jarsのjarファイルでクラスをパッケージ化します。

installdir/buildjars/customsecuritymodules.jardocsサブフォルダに含まれるインタフェースのJavadocを要約します。

カスタム暗号化モジュール

カスタム暗号化モジュールは、次に示すようにインタフェース oracle.edq.security.module.custom.interfaces.CustomEncryptionModuleを実装する必要があります。

CustomEncryptionModule


/*
 * Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved.
 */
package oracle.edq.security.module.custom.interfaces;
 
import java.nio.file.Path;
import java.util.Properties;
 
/**
 * Interface implemented by custom encryption modules.
 */
 
public interface CustomEncryptionModule {
 
  /**
   * Initialize the encryption module.
   *
   * @param localconfig The local configuration area.  This can be used to locate or store extra files
   * required by the module.
   * @param props The module properties
   * @param persist If <code>true</code> the module data can be persisted for future use.
   * This flag will be <code>false</code> if the module is being initalized for a "dryrun" encryption migration.
   * In this case no permanent changes should be made in the file system.
   *
   * @throws Exception If initialization failed.
   */
 
  void initEncryption(Path localconfig, Properties props, boolean persist) throws Exception;
 
  /**
   * Encrypt some data.
   *
   * @param in The plain text
   *
   * @return The cipher text
   *
   * @throws Exception If encryption failed
   */
 
  byte [] encrypt(byte [] in) throws Exception;
 
  /**
   * Decrypt some data.
   *
   * @param in The cipher text
   *
   * @return The plain text
   *
   * @throws Exception If decryption failed
   */
 
  byte [] decrypt(byte [] in) throws Exception;
}

暗号化モジュールがoracle.edq.security.module.custom.interfaces.CustomCredentialsModuleも実装している場合は、資格証明ストアとして機能します。この場合、initCredentialsメソッドはコールされません。

カスタム資格証明ストア

カスタム暗号化モジュールは、次に示すようにインタフェース oracle.edq.security.module.custom.interfaces.CustomCredentialsModuleを実装する必要があります。

CustomCredentialsModule


/*
 * Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved.
 */
package oracle.edq.security.module.custom.interfaces;
 
import java.nio.file.Path;
import java.util.Properties;
 
/**
 * Interface implemented by custom credentials modules.
 */
 
public interface CustomCredentialsModule {
 
  /**
   * Get the prefix used to extract properties recognized by the module.  The default value is "cred".
   *
   * @return The prefix
   */
 
  default String credsPrefix() {
    return "cred";
  }
 
  /**
   * Initialize the credentials provider for credentials-only use.
   *
   * @param localconfig The local configuration area
   * @param props The module properties
   *
   * @throws Exception If initialization failed.
   */
 
  void initCredentials(Path localconfig, Properties props) throws Exception;
 
  /**
   * Attempt to get credentials.
   *
   * @param props The filtered property set.
   *
   * @return The credentials, or <code>null</code> if not found
   *
   * @throws Exception If an error ocurred
   */
 
  Credentials getCredentials(Properties props) throws Exception;
 
  /**
   * Credentials result class.
   */
 
  final class Credentials {
 
    private String  username;
    private String  password;
 
    /**
     * Constructor.
     *
     * @param username The user name
     * @param password The password
     */
 
    public Credentials(String username, String password) {
      this.username = username;
      this.password = password;
    }
 
    /**
     * Get the user name.
     *
     * @return The user name
     */
 
    public String getUsername() {
      return username;
    }
 
    /**
     * Get the password.
     *
     * @return The password
     */
 
    public String getPassword() {
      return password;
    }
  }
}