4.2.6 キーストアへのデータベース・パスワードの格納

PGXでは、データベースからメモリーにデータを読み込むためにデータベース・アカウントが必要です。アカウントは、権限の低いアカウントである必要があります(グラフ・データを使用したセキュリティのベスト・プラクティスを参照)。

データベースからのデータの読取りで説明されているように、トークンがそのデータベース・ユーザーに対して有効であるかぎり、追加の認証を指定しなくてもデータベースからグラフ・サーバーにデータを読み込むことができます。ただし、別のユーザーからグラフにアクセスする場合は、そのユーザーのパスワードが保護のためにJavaキーストア・ファイルに格納されているかぎり、それは可能です。

JDKにバンドルされたkeytoolコマンドを使用して、そのようなキーストア・ファイルをコマンドラインで生成できます。例として次のスクリプトを参照してください。

# Add a password for the 'database1' connection
keytool -importpass -alias database1 -keystore keystore.p12
# 1. Enter the password for the keystore
# 2. Enter the password for the database
 
# Add another password (for the 'database2' connection)
keytool -importpass -alias database2 -keystore keystore.p12
 
# List what's in the keystore using the keytool
keytool -list -keystore keystore.p12

Javaバージョン8以下を使用している場合は、前述の例のkeytoolコマンドに追加パラメータ-storetype pkcs12を渡す必要があります。

複数のパスワードを1つのキーストア・ファイルに格納できます。各パスワードは、指定された別名を使用して参照できます。

プロパティ・グラフ・スキーマからロードするPGXグラフ構成ファイルを記述します

次に、PGXグラフ構成ファイルをJSON形式で作成します。このファイルは、データのロード元、データの外観、および使用するキーストア別名をPGXに伝えます。次の例に、Oracleプロパティ・グラフ形式で格納されたデータを読み取るグラフ構成を示します。

{
  "format": "pg",
  "db_engine": "rdbms",
  "name": "hr",
  "jdbc_url": "jdbc:oracle:thin:@myhost:1521/orcl",
  "username": "hr",
  "keystore_alias": "database1",
  "vertex_props": [{
    "name": "COUNTRY_NAME",
    "type": "string"
  }, {
    "name": "DEPARTMENT_NAME",
    "type": "string"
  }, {
    "name": "SALARY",
    "type": "double"
  }],
  "partition_while_loading": "by_label",
  "loading": {
    "load_vertex_labels": true,
    "load_edge_label": true
  }
}

(意味とデフォルト値を含む、使用可能な構成フィールドの完全なリストは、グラフ構成のオプションを参照してください。)

または、PGXグラフ構成ファイルを記述し、グラフをリレーショナル表から直接ロードします

次の例では、HRサンプル・データのサブセットをリレーショナル表からPGXにグラフとして直接ロードします。構成ファイルでは、頂点およびエッジ・プロバイダの概念を使用して、リレーショナル形式からグラフ形式へのマッピングを指定します。

ノート:

vertex_providersプロパティおよびedge_providersプロパティを指定すると、データがグラフの最適化表現にロードされます。

{
    "name":"hr",
    "jdbc_url":"jdbc:oracle:thin:@myhost:1521/orcl",
    "username":"hr",
    "keystore_alias":"database1",
    "vertex_id_strategy": "no_ids",
    "vertex_providers":[
        {
            "name":"Employees",
            "format":"rdbms",
            "database_table_name":"EMPLOYEES",
            "key_column":"EMPLOYEE_ID",
            "key_type": "string",
            "props":[
                {
                    "name":"FIRST_NAME",
                    "type":"string"
                },
                {
                    "name":"LAST_NAME",
                    "type":"string"
                },
                {
                    "name":"EMAIL",
                    "type":"string"
                },
                {
                    "name":"SALARY",
                    "type":"long"
                }
            ]
        },
        {
            "name":"Jobs",
            "format":"rdbms",
            "database_table_name":"JOBS",
            "key_column":"JOB_ID",
            "key_type": "string",
            "props":[
                {
                    "name":"JOB_TITLE",
                    "type":"string"
                }
            ]
        },
        {
            "name":"Departments",
            "format":"rdbms",
            "database_table_name":"DEPARTMENTS",
            "key_column":"DEPARTMENT_ID",
            "key_type": "string",
            "props":[
                {
                    "name":"DEPARTMENT_NAME",
                    "type":"string"
                }
            ]
        }
    ],
    "edge_providers":[
        {
            "name":"WorksFor",
            "format":"rdbms",
            "database_table_name":"EMPLOYEES",
            "key_column":"EMPLOYEE_ID",
            "source_column":"EMPLOYEE_ID",
            "destination_column":"EMPLOYEE_ID",
            "source_vertex_provider":"Employees",
            "destination_vertex_provider":"Employees"
        },
        {
            "name":"WorksAs",
            "format":"rdbms",
            "database_table_name":"EMPLOYEES",
            "key_column":"EMPLOYEE_ID",
            "source_column":"EMPLOYEE_ID",
            "destination_column":"JOB_ID",
            "source_vertex_provider":"Employees",
            "destination_vertex_provider":"Jobs"
        },
        {
            "name":"WorkedAt",
            "format":"rdbms",
            "database_table_name":"JOB_HISTORY",
            "key_column":"EMPLOYEE_ID",
            "source_column":"EMPLOYEE_ID",
            "destination_column":"DEPARTMENT_ID",
            "source_vertex_provider":"Employees",
            "destination_vertex_provider":"Departments",
            "props":[
                {
                    "name":"START_DATE",
                    "type":"local_date"
                },
                {
                    "name":"END_DATE",
                    "type":"local_date"
                }
            ]
        }
    ]
}

データの読取り

ここで、次のいずれかの方法を使用して、キーストアと構成ファイルの両方をPGXに渡すことにより、データベースに接続してデータを読み取るようPGXに指示できます。

  • グラフ・シェルで対話的に

    グラフ・シェルを使用している場合は、--secret_storeオプションで起動します。キーストア・パスワードを入力し、現在のセッションにキーストアをアタッチするよう要求されます。次に例を示します。

    cd /opt/oracle/graph
    ./bin/opg4j --secret_store /etc/my-secrets/keystore.p12
     
     enter password for keystore /etc/my-secrets/keystore.p12:
    

    シェルの内部では、通常のPGX APIを使用し、readGraphWithProperties APIに書き込んだJSONファイルを渡すことで、グラフをメモリーに読み込むことができます。

    opg4j> var graph = session.readGraphWithProperties("config.json")
    graph ==> PgxGraph[name=hr,N=215,E=415,created=1576882388130]
    
  • PGXの事前ロード済グラフとして
    サーバー管理者として、サーバー起動時にメモリーにグラフをロードするようPGXに指定できます。そのためには、/etc/oracle/graph/pgx.confにあるPGX構成ファイルを変更し、グラフ構成ファイルのパスをpreload_graphsセクションに追加します。次に例を示します。
    {
      ...
      "preload_graphs": [{
        "name": "hr", 
        "path": "/path/to/config.json"
      }],
      "authorization": [{
        "pgx_role": "GRAPH_DEVELOPER",
        "pgx_permissions": [{
          "preloaded_graph": "hr",
          "grant": "read"
        }]
      },	
    	....
      ]
    }
    rootユーザーとして、/etc/systemd/system/pgx.serviceにあるサービス・ファイルを編集し、ExecStartコマンドを変更してパスワードを含むキーストアの場所を指定します。
    
    ExecStart=/bin/bash start-server --secret-store /etc/keystore.p12

    ノート:

    これを機能させるため、/etc/keystore.p12をパスワードで保護しないでください。かわりに、oraclegraphユーザーのみが読取り可能なファイル・システム権限によってファイルを保護します。
    ファイルを編集したら、次を使用して変更をリロードします。
    sudo systemctl daemon-reload
    最後に、サーバーを起動します。
    sudo systemctl start pgx
  • Javaアプリケーション

    キーストアをJavaアプリケーションに登録するには、PgxSessionオブジェクトでregisterKeystore() APIを使用します。次に例を示します。

    import oracle.pgx.api.*;
     
    class Main {
       
      public static void main(String[] args) throws Exception {
        String baseUrl = args[0];
        String keystorePath = "/etc/my-secrets/keystore.p12";
        char[] keystorePassword = args[1].toCharArray();
        String graphConfigPath = args[2];
        ServerInstance instance = Pgx.getInstance(baseUrl);
        try (PgxSession session = instance.createSession("my-session")) {
          session.registerKeystore(keystorePath, keystorePassword);
          PgxGraph graph = session.readGraphWithProperties(graphConfigPath);
          System.out.println("N = " + graph.getNumVertices() + " E = " + graph.getNumEdges());
        }
      }
    }
    
    前述のサンプル・プログラムは、Oracle Graphクライアント・パッケージを使用してコンパイルおよび実行できます。次に例を示します。
    cd $GRAPH_CLIENT
    // create Main.java with above contents
    javac -cp 'lib/*' Main.java
    java -cp '.:conf:lib/*' Main http://myhost:7007 MyKeystorePassword path/to/config.json
    

グラフ・クライアント・アプリケーションのセキュア・コーディングのヒント

グラフ・クライアント・アプリケーションを作成する場合は、いずれのファイルまたはコードにもパスワードやその他のシークレットをクリア・テキストで格納しないでください。

コマンドライン引数からパスワードやその他のシークレットを受け入れないでください。かわりに、JDKからConsole.html#readPassword()を使用してください。