From 257e5d60a95879af2e5f5e33abd0b979ee456b49 Mon Sep 17 00:00:00 2001 From: "hlem@ca.ibm.com" Date: Mon, 16 Sep 2024 12:04:02 -0400 Subject: [PATCH] add iam auth for ibmcloud --- cmd/infracost/configure.go | 45 ++++++++++++++++++++++++++++++++ go.mod | 11 ++++++++ go.sum | 32 ++++++++++++++++++++++- internal/apiclient/client.go | 26 +++++++++++++----- internal/apiclient/pricing.go | 45 +++++++++++++++++++++++++++----- internal/config/config.go | 8 +++++- internal/config/configuration.go | 9 +++++++ internal/config/credentials.go | 10 +++++++ 8 files changed, 171 insertions(+), 15 deletions(-) diff --git a/cmd/infracost/configure.go b/cmd/infracost/configure.go index 9cf8561e4b4..23be7127f56 100644 --- a/cmd/infracost/configure.go +++ b/cmd/infracost/configure.go @@ -14,6 +14,9 @@ import ( var supportedConfigureKeys = map[string]struct{}{ "api_key": {}, + "ibm_cloud_api_key": {}, + "ibm_cloud_iam_url": {}, + "ibm_usage": {}, "currency": {}, "pricing_api_endpoint": {}, "enable_dashboard": {}, @@ -85,6 +88,15 @@ func configureSetCmd(ctx *config.RunContext) *cobra.Command { case "api_key": ctx.Config.Credentials.APIKey = value saveCredentials = true + case "ibm_cloud_api_key": + ctx.Config.Credentials.IBMCloudApiKey = value + saveCredentials = true + case "ibm_cloud_iam_url": + ctx.Config.Credentials.IBMCloudIAMUrl = value + saveCredentials = true + case "ibm_usage": + ctx.Config.Configuration.IBMUsage = value + saveConfiguration = true case "tls_insecure_skip_verify": if value == "" { ctx.Config.Configuration.TLSInsecureSkipVerify = nil @@ -218,6 +230,36 @@ func configureGetCmd(ctx *config.RunContext) *cobra.Command { ) ui.PrintWarning(cmd.ErrOrStderr(), msg) } + case "ibm_cloud_api_key": + value = ctx.Config.Credentials.IBMCloudApiKey + + if value == "" { + msg := fmt.Sprintf("No IBM Cloud API key in your saved config (%s).\nSet an API key using %s.", + config.CredentialsFilePath(), + ui.PrimaryString("infracost configure set ibm_cloud_api_key MY_API_KEY"), + ) + ui.PrintWarning(cmd.ErrOrStderr(), msg) + } + case "ibm_cloud_iam_url": + value = ctx.Config.Credentials.IBMCloudIAMUrl + + if value == "" { + msg := fmt.Sprintf("No IBM Cloud IAM Url in your saved config (%s).\nSet an IAM Url using %s.", + config.CredentialsFilePath(), + ui.PrimaryString("infracost configure set ibm_cloud_iam_url URL"), + ) + ui.PrintWarning(cmd.ErrOrStderr(), msg) + } + case "ibm_usage": + value = ctx.Config.Configuration.IBMUsage + + if value == "" { + msg := fmt.Sprintf("No IBM usage path in your saved config (%s), defaulting to the default usage.\nSet a path using %s.", + config.ConfigurationFilePath(), + ui.PrimaryString("infracost configure set ibm_usage GC_PATH"), + ) + ui.PrintWarning(cmd.ErrOrStderr(), msg) + } case "currency": value = ctx.Config.Configuration.Currency @@ -287,10 +329,13 @@ func supportedConfigureSettingsOutput(description string) string { settings := ` Supported settings: - api_key: Infracost API key + - ibm_cloud_api_key: IBM Cloud Api Key + - ibm_cloud_iam_url: IBM Cloud IAM Url - pricing_api_endpoint: endpoint of the Cloud Pricing API - currency: convert output from USD to your preferred currency - tls_insecure_skip_verify: skip TLS certificate checks for a self-hosted Cloud Pricing API - tls_ca_cert_file: verify certificate of a self-hosted Cloud Pricing API using this CA certificate + - ibm_usage: global catalog object with usage data ` return fmt.Sprintf("%s.\n%s", description, settings) diff --git a/go.mod b/go.mod index 065ad63bd30..4ca7313125c 100644 --- a/go.mod +++ b/go.mod @@ -91,6 +91,7 @@ require ( ) require ( + github.com/IBM/go-sdk-core/v5 v5.17.5 github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1 github.com/awslabs/goformation/v7 v7.2.5 github.com/dave/dst v0.27.3 @@ -130,6 +131,7 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect @@ -144,8 +146,14 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/frankban/quicktest v1.14.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-openapi/errors v0.21.0 // indirect + github.com/go-openapi/strfmt v0.22.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect @@ -165,11 +173,13 @@ require ( github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lib/pq v1.8.0 // indirect github.com/lithammer/fuzzysearch v1.1.5 // indirect github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/runc v1.1.5 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect @@ -185,6 +195,7 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a // indirect go.mozilla.org/sops/v3 v3.7.2 // indirect golang.org/x/term v0.20.0 // indirect diff --git a/go.sum b/go.sum index 713ba3ea53e..bba7562e232 100644 --- a/go.sum +++ b/go.sum @@ -283,6 +283,8 @@ github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nu github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/IBM/go-sdk-core/v5 v5.17.5 h1:AjGC7xNee5tgDIjndekBDW5AbypdERHSgib3EZ1KNsA= +github.com/IBM/go-sdk-core/v5 v5.17.5/go.mod h1:KsAAI7eStAWwQa4F96MLy+whYSh39JzNjklZRbN/8ns= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= @@ -368,6 +370,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= @@ -614,7 +618,11 @@ github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -644,6 +652,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= +github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -652,9 +662,19 @@ github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwoh github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.22.1 h1:5Ky8cybT4576C6Ffc+8gYji/wRXCo6Ozm8RaWjPI6jc= +github.com/go-openapi/strfmt v0.22.1/go.mod h1:OfVoytIXJasDkkGvkb1Cceb3BPyMOwk1FgmyyEw7NYg= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= +github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -1033,6 +1053,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -1141,15 +1163,20 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8= github.com/onsi/ginkgo/v2 v2.3.1/go.mod h1:Sv4yQXwG5VmF7tm3Q5Z+RWUpPo24LF1mpnz2crUb8Ys= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -1410,6 +1437,8 @@ github.ibm.com/dataops/go-cty-yaml v1.0.0 h1:YjRNaUC1o7aNNZilu3g+/qBLOH+H4sZC8qt github.ibm.com/dataops/go-cty-yaml v1.0.0/go.mod h1:8os/a4GlMl7b55xB6OJt/UwXJnzqJ11PnJbB6wiGtMQ= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a h1:N7VD+PwpJME2ZfQT8+ejxwA4Ow10IkGbU0MGf94ll8k= go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a/go.mod h1:YDKUvO0b//78PaaEro6CAPH6NqohCmL2Cwju5XI2HoE= go.mozilla.org/sops/v3 v3.7.2 h1:LNThLKe/pb80eGyAOFiWKP1Znqp1GQO2hqvuQOCmy5o= @@ -2117,6 +2146,7 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= diff --git a/internal/apiclient/client.go b/internal/apiclient/client.go index 8c199043aa1..ea7f6812777 100644 --- a/internal/apiclient/client.go +++ b/internal/apiclient/client.go @@ -8,6 +8,7 @@ import ( "io" "net/http" + "github.com/IBM/go-sdk-core/v5/core" "github.com/google/uuid" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -18,10 +19,11 @@ import ( ) type APIClient struct { - endpoint string - apiKey string - tlsConfig *tls.Config - uuid uuid.UUID + endpoint string + apiKey string + ibmAuthenticator *core.IamAuthenticator + tlsConfig *tls.Config + uuid uuid.UUID } type GraphQLQuery struct { @@ -67,7 +69,10 @@ func (c *APIClient) doRequest(method string, path string, d interface{}) ([]byte return []byte{}, errors.Wrap(err, "Error generating request") } - c.AddAuthHeaders(req) + err = c.AddAuthHeaders(req) + if err != nil { + return []byte{}, errors.Wrap(err, "Error sending API request") + } // Use the DefaultTransport since this handles the HTTP/HTTPS proxy and other defaults // and add the TLS config that was passed into the client @@ -108,12 +113,21 @@ func (c *APIClient) AddDefaultHeaders(req *http.Request) { req.Header.Set("User-Agent", userAgent()) } -func (c *APIClient) AddAuthHeaders(req *http.Request) { +func (c *APIClient) AddAuthHeaders(req *http.Request) error { c.AddDefaultHeaders(req) req.Header.Set("X-Api-Key", c.apiKey) if c.uuid != uuid.Nil { req.Header.Set("X-Infracost-Trace-Id", fmt.Sprintf("cli=%s", c.uuid.String())) } + if c.ibmAuthenticator != nil { + token, err := c.ibmAuthenticator.GetToken() + if err != nil { + fmt.Println(err) + return err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + } + return nil } func userAgent() string { diff --git a/internal/apiclient/pricing.go b/internal/apiclient/pricing.go index 4217b6a93c3..635be3fe20d 100644 --- a/internal/apiclient/pricing.go +++ b/internal/apiclient/pricing.go @@ -6,6 +6,7 @@ import ( "fmt" "os" + "github.com/IBM/go-sdk-core/v5/core" "github.com/infracost/infracost/internal/config" "github.com/infracost/infracost/internal/schema" @@ -41,7 +42,9 @@ func NewPricingAPIClient(ctx *config.RunContext) *PricingAPIClient { currency = "USD" } - tlsConfig := tls.Config{} // nolint: gosec + tlsConfig := tls.Config{ + MinVersion: tls.VersionTLS12, + } // nolint: gosec if ctx.Config.TLSCACertFile != "" { rootCAs, _ := x509.SystemCertPool() @@ -65,16 +68,44 @@ func NewPricingAPIClient(ctx *config.RunContext) *PricingAPIClient { tlsConfig.RootCAs = rootCAs } - if ctx.Config.TLSInsecureSkipVerify != nil { - tlsConfig.InsecureSkipVerify = *ctx.Config.TLSInsecureSkipVerify + // disallow this setting + // if ctx.Config.TLSInsecureSkipVerify != nil { + // tlsConfig.InsecureSkipVerify = *ctx.Config.TLSInsecureSkipVerify + //} + + var iamAuthenticator *core.IamAuthenticator = nil + authenticatorBuilder := core.NewIamAuthenticatorBuilder() + if ctx.Config.IBMCloudIAMUrl != "" { + fmt.Println("Configured IAM URL", ctx.Config.IBMCloudIAMUrl) + authenticatorBuilder.SetURL(ctx.Config.IBMCloudIAMUrl) + } else { + fmt.Println("No IBM_CLOUD_IAM_URL credential set, defaults to production.") + } + if ctx.Config.IBMCloudApiKey != "" { + if len(ctx.Config.IBMCloudApiKey) != 44 { + fmt.Println("IBM_CLOUD_API_KEY's length is not 44... Is this a proper IAM api key?") + } + authenticatorBuilder.SetApiKey(ctx.Config.IBMCloudApiKey) + authenticator, err := authenticatorBuilder.Build() + if err != nil { + log.Error("Unable to init authenticator", err) + } + iamAuthenticator = authenticator + } else { + fmt.Println("No IBM_CLOUD_API_KEY credential set") + } + + if ctx.Config.APIKey == "" && iamAuthenticator == nil { + fmt.Println("No authentication method specified") } return &PricingAPIClient{ APIClient: APIClient{ - endpoint: ctx.Config.PricingAPIEndpoint, - apiKey: ctx.Config.APIKey, - tlsConfig: &tlsConfig, - uuid: ctx.UUID(), + endpoint: ctx.Config.PricingAPIEndpoint, + apiKey: ctx.Config.APIKey, + ibmAuthenticator: iamAuthenticator, + tlsConfig: &tlsConfig, + uuid: ctx.UUID(), }, Currency: currency, EventsDisabled: ctx.Config.EventsDisabled, diff --git a/internal/config/config.go b/internal/config/config.go index b7805cf39ba..38316c61786 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -71,6 +71,10 @@ type Config struct { Parallelism *int `envconfig:"PARALLELISM"` APIKey string `envconfig:"API_KEY"` + IBMCloudApiKey string `envconfig:"IBM_CLOUD_API_KEY"` + IBMCloudIAMUrl string `envconfig:"IBM_CLOUD_IAM_URL"` + IBMUsageDefault string `yaml:"ibm_default_usage,omitempty" envconfig:"IBM_DEFAULT_USAGE"` + IBMUsage string `yaml:"ibm_usage,omitempty" envconfig:"IBM_USAGE"` PricingAPIEndpoint string `yaml:"pricing_api_endpoint,omitempty" envconfig:"PRICING_API_ENDPOINT"` DefaultPricingAPIEndpoint string `yaml:"default_pricing_api_endpoint,omitempty" envconfig:"DEFAULT_PRICING_API_ENDPOINT"` DashboardAPIEndpoint string `yaml:"dashboard_api_endpoint,omitempty" envconfig:"DASHBOARD_API_ENDPOINT"` @@ -134,8 +138,10 @@ func DefaultConfig() *Config { LogLevel: "", NoColor: false, - DefaultPricingAPIEndpoint: "https://pricing.api.infracost.io", + DefaultPricingAPIEndpoint: "https://cost-management.api.cloud.ibm.com/iam-proxy", PricingAPIEndpoint: "", + IBMUsageDefault: "https://globalcatalog.cloud.ibm.com/api/v1/infracost-default-usage?include=metadata", + IBMUsage: "", DashboardAPIEndpoint: "https://dashboard.api.infracost.io", DashboardEndpoint: "https://dashboard.infracost.io", EnableDashboard: false, diff --git a/internal/config/configuration.go b/internal/config/configuration.go index 5ecbd318e39..5f37d7658d6 100644 --- a/internal/config/configuration.go +++ b/internal/config/configuration.go @@ -20,6 +20,7 @@ type Configuration struct { TLSInsecureSkipVerify *bool `yaml:"tls_insecure_skip_verify,omitempty"` TLSCACertFile string `yaml:"tls_ca_cert_file,omitempty"` EnableCloud *bool `yaml:"enable_cloud"` + IBMUsage string `yaml:"ibm_usage"` EnableCloudUpload *bool `yaml:"enable_cloud_upload"` } @@ -68,6 +69,14 @@ func loadConfiguration(cfg *Config) error { cfg.TLSCACertFile = cfg.Configuration.TLSCACertFile } + if cfg.IBMUsage == "" { + cfg.IBMUsage = cfg.Configuration.IBMUsage + } + + if cfg.IBMUsage == "" { + cfg.IBMUsage = cfg.IBMUsageDefault + } + return nil } diff --git a/internal/config/credentials.go b/internal/config/credentials.go index 0d884b4a74e..742fe6e7ee3 100644 --- a/internal/config/credentials.go +++ b/internal/config/credentials.go @@ -15,6 +15,8 @@ var credentialsVersion = "0.1" type Credentials struct { Version string `yaml:"version"` APIKey string `yaml:"api_key,omitempty"` + IBMCloudApiKey string `yaml:"ibm_cloud_api_key,omitempty"` + IBMCloudIAMUrl string `yaml:"ibm_cloud_iam_url,omitempty"` PricingAPIEndpoint string `yaml:"pricing_api_endpoint,omitempty"` } @@ -43,6 +45,14 @@ func loadCredentials(cfg *Config) error { cfg.APIKey = cfg.Credentials.APIKey } + if cfg.IBMCloudApiKey == "" { + cfg.IBMCloudApiKey = cfg.Credentials.IBMCloudApiKey + } + + if cfg.IBMCloudIAMUrl == "" { + cfg.IBMCloudIAMUrl = cfg.Credentials.IBMCloudIAMUrl + } + return nil }