GeekFactory

int128.hatenablog.com

Spring Boot + Gradleで依存関係のバージョンが下がる場合の対応策

GradleでSpring Boot Pluginを利用している場合、依存関係のバージョンが勝手に下がることがあります。例えば、

という依存関係がある場合、アプリのプロジェクトには spock-core-1.1-groovy-2.4 が入る気がしますが、実際には spock-core-1.0-groovy-2.4 の古いバージョンが入ります。

これは、spring-boot-dependenciesのpom.xmlで定義されているバージョンが優先されてしまうためのようです。

https://github.com/spring-projects/spring-boot/blob/1.5.x/spring-boot-dependencies/pom.xml

<spock.version>1.0-groovy-2.4</spock.version>

アプリのプロジェクトで新しいバージョンの依存関係を定義すれば解決します。

  • テスティングフレームワークのプロジェクト → spock-core-1.1-groovy-2.4
  • アプリのプロジェクト → テスティングフレームワークのプロジェクト
  • アプリのプロジェクト → spock-core-1.1-groovy-2.4

もしくは、ビルドスクリプトに以下を追記して、spring-boot-dependenciesのバージョンを上書きします。

ext.'spock.version' = '1.1-groovy-2.4'

extに書いた内容はサブプロジェクトにも適用されるので、後者が安心ですね。

Gradle Swagger Generator Plugin 2.6.0をリリースした

Gradle Swagger Generator Plugin 2.6.0をリリースしました。OpenAPI YAMLのバリデーション、コード生成、Swagger UI生成を行うためのプラグインです。

github.com

New features

複数のOpenAPI YAMLを扱う場合に簡潔に記述できるようになりました。これまではYAMLごとに自分でタスクを定義する必要がありましたが、2.6.0からは swaggerSources ブロックに列挙できるようになりました。

swaggerSources {
    petstoreV1 {
        inputFile = file('v1-petstore.yaml')
        code {
            language = 'spring'
            configFile = file('v1-config.json')
        }
    }
    petstoreV2 {
        inputFile = file('v2-petstore.yaml')
        code {
            language = 'spring'
            configFile = file('v2-config.json')
        }
    }
}

コードやSwagger UIを生成する前にYAMLバリデーションを行いたい場合は下記の1行を付け足します。

        code {
            language = 'spring'
            configFile = file('v2-config.json')
            dependsOn validation    // ←追加
        }

また、外部リポジトリからテンプレートを読み込めるようになりました。複数のプロジェクトで共通のテンプレートを利用したい場合に役に立ちます。

repositories {
  // NexusやArtifactoryのリポジトリを指定
  maven {
    url 'https://example.com/nexus-or-artifactory'
  }
  jcenter()
}

dependencies {
  swaggerCodegen 'io.swagger:swagger-codegen-cli:2.2.3'
  // NexusやArtifactoryにpublishされたテンプレートを指定
  swaggerTemplate 'com.example:swagger-templates:1.0.0'
}

swaggerSources {
  petstore {
    inputFile = file('petstore.yaml')
    code {
      language = 'spring'
      // テンプレートJAR内のパスを指定
      templateDir = file("${resolveSwaggerTemplate.destinationDir}/spring-mvc")
    }
  }
}

このように、大規模なプロジェクトでSwagger CodegenやSwagger UIを活用する場合に有用な機能を追加しています。

詳しくはREADMEやサンプルプロジェクトを参照してください。

CloudFront→ELB→EC2構成におけるIPアドレスのアクセス制御

AWSでCloudFront → ELB → EC2の構成を採用する場合に、IPアドレスによるアクセス制御を行う方法を説明します。

方法1: EC2上のWebサーバによるアクセス制御

CloudFrontやELBはリクエストを受けると x-forwarded-for ヘッダにクライアントのIPアドレスを付与します。 このヘッダを利用してIPアドレスによるアクセス制御を実現できます。

CloudFrontとELBを組み合わせる場合は下記のようなヘッダを受け取ります。

クライアント
↓
CloudFront
↓ x-forwarded-for: <クライアントのIPアドレス>
ELB
↓ x-forwarded-for: <クライアントのIPアドレス>, <CloudFrontエッジのIPアドレス>
EC2

クライアントがヘッダを偽装した場合も考慮しておきましょう。もし、クライアントが x-forwarded-for ヘッダを付けてアクセスした場合は下記のようになります。

クライアント
↓ x-forwarded-for: <クライアントが付けた内容>
CloudFront
↓ x-forwarded-for: <クライアントが付けた内容>, <クライアントのIPアドレス>
ELB
↓ x-forwarded-for: <クライアントが付けた内容>, <クライアントのIPアドレス>, <CloudFrontエッジのIPアドレス>
EC2

したがって、 x-forwarded-for ヘッダをカンマで区切って右から2番目の要素を取得すると、クライアントのIPアドレスを取り出すことができます。

Apacheを利用している場合は SetEnvIf正規表現を指定してIPアドレスをチェックします。例えば、 10.20.30.40 に対してアクセスを許可するには下記の設定になります。

<Directory "/var/www/html">
  SetEnvIf x-forwarded-for "(:?^| )10\.20\.30\.40, [\d.]+$" permit_staging
  Order Deny,Allow
  Deny from all
  Allow from env=permit_staging
</Directory>

Apache 2.4からはmod_remoteipモジュールが利用できますが、ヘッダの右から2番目の要素といった指定はできないようです。 クライアントがヘッダを偽装するケースを考慮すると、現時点では正規表現が安全と思います。

CloudFrontやELBが付与する x-forwarded-for ヘッダの仕様は下記を参照してください。

docs.aws.amazon.com

docs.aws.amazon.com

方法2: WAFによるアクセス制御

CloudFrontにWAF(Web Application Firewall)のルールをアタッチすることで、IPアドレスによるアクセス制御を実現できます。 ただし、CloudFrontからELBにアクセスできるようにセキュリティグループを開けておく必要があります。 かなり広いIPアドレスブロックを開けておく必要があるため、攻撃者からELBに直接アクセスされるリスクがあります。

docs.aws.amazon.com